tsn.c (311708B)
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: Manage chip specific functionality for TSN implementation on GH2. 8 */ 9 10 #include <shared/bsl.h> 11 #include <sal/core/time.h> 12 #include <soc/drv.h> 13 #include <soc/debug.h> 14 #include <soc/mem.h> 15 #include <soc/profile_mem.h> 16 #include <soc/scache.h> 17 #include <bcm/tsn.h> 18 #include <bcm/port.h> 19 #include <bcm/error.h> 20 #include <bcm/types.h> 21 #include <bcm_int/esw_dispatch.h> 22 #include <bcm_int/esw/tsn.h> 23 #include <bcm_int/esw/stack.h> 24 #include <bcm_int/esw/hurricane3.h> 25 #include <bcm_int/esw/greyhound2.h> 26 #include <bcm_int/esw_dispatch.h> 27 #ifdef BCM_WARM_BOOT_SUPPORT 28 #include <soc/scache.h> 29 #include <bcm_int/esw/switch.h> 30 #endif /* BCM_WARM_BOOT_SUPPORT */ 31 32 #if defined(BCM_GREYHOUND2_SUPPORT) && defined(BCM_TSN_SUPPORT) 33 34 #if defined(BCM_TSN_SR_SUPPORT) 35 /* 36 * SR Auto Learn management: HW platform specific constants 37 */ 38 39 /* TX & RX flow index 0 is invalid, thus only 4095 are available */ 40 #define GH2_SR_AUTO_LEARN_TX_FLOW_SIZE (4095) 41 #define GH2_SR_AUTO_LEARN_RX_FLOW_SIZE (4095) 42 43 /* 44 * Default value (reset value) for Auto Learn Group Ports 45 * Note: 46 * 0 is not a INVALID value of L2MC 47 * but there are two HW fields ING_SR_ENABLE & ING_SR_PORT_ROLE to make 48 * sure the port is SR redudant port. 49 */ 50 #define GH2_SR_AUTO_LEARN_GROUP_PORTS_L2MC_DEFAULT_VALUE (0) 51 #define GH2_SR_AUTO_LEARN_GROUP_PORTS_MACP_DEFAULT_VALUE (0) 52 53 /* 54 * SR flow management: HW platform specific constants 55 */ 56 #define TSN_SRFLOWS_RX_ACCEPT_SIZE_MIN 512 57 #define TSN_SRFLOWS_RX_ACCEPT_SIZE_MAX 65536 58 #define TSN_SRFLOWS_RX_ACCEPT_POWER_MIN 9 59 #define TSN_SRFLOWS_RX_ACCEPT_POWER_MAX 16 60 #define TSN_SRFLOWS_RX_WINDOW_SIZE_MIN 64 61 #define TSN_SRFLOWS_RX_WINDOW_SIZE_MAX 4096 62 #define TSN_SRFLOWS_RX_WINDOW_POWER_MIN 6 63 #define TSN_SRFLOWS_RX_WINDOW_POWER_MAX 12 64 #define TSN_SRFLOWS_RX_SNPOOL_SIZE_MIN 64 65 #define TSN_SRFLOWS_RX_SNPOOL_SIZE_MAX 1024 66 #define TSN_SRFLOWS_RX_SNPOOL_POWER_MIN 6 67 #define TSN_SRFLOWS_RX_SNPOOL_POWER_MAX 10 68 #define TSN_SRFLOWS_RX_SNPOOL_SIZE_COUNT \ 69 (TSN_SRFLOWS_RX_SNPOOL_POWER_MAX - TSN_SRFLOWS_RX_SNPOOL_POWER_MIN + 1) 70 #define TSN_SRFLOWS_RX_SNPOOL_IDX_MAX \ 71 (TSN_SRFLOWS_RX_SNPOOL_SIZE_COUNT - 1) 72 #define TSN_SRFLOWS_RX_SN_HIST_POOLS 4 73 #define TSN_SRFLOWS_RX_SN_HIST_POOL_SIZE 1024 74 #define TSN_SRFLOWS_RX_SN_HIST_POOL_POWER 10 75 #define TSN_SRFLOWS_RX_SN_HIST_MEM_SIZE 256 76 #define TSN_SRFLOWS_RX_SN_HIST_MEM_POWER 8 77 #define TSN_SRFLOWS_RX_SN_HIST_SUB_INDEX \ 78 (TSN_SRFLOWS_RX_SN_HIST_POOL_POWER - TSN_SRFLOWS_RX_SN_HIST_MEM_POWER) 79 #define TSN_SRFLOWS_RX_SN_HIST_SUB_POOLS 4 80 #define TSN_SRFLOWS_RX_SN_HIST_BLOCK_SIZE 64 81 #define TSN_SRFLOWS_RX_AGE_TIME_MAX 32768 82 #define TSN_SRFLOWS_SEQNUM_VALUE_MAX 65535 83 #define TSN_SRFLOWS_FLOWID_TX_MASK 0x1000 84 #define TSN_SRFLOWS_DEFAULT_NEXT_SN 0 85 86 /* SR flow management: sequence number slice entry */ 87 typedef struct tsn_sr_seqnum_slice_s { 88 int index; /* Pool index */ 89 int entry; /* Entry in the pool */ 90 int offset; /* Offset in the entry */ 91 int power; /* size in power of bits */ 92 struct tsn_sr_seqnum_slice_s *next; 93 } tsn_sr_seqnum_slice_t; 94 95 /* SR flow management bookkeeping */ 96 typedef struct gh2_tsn_sr_flows_bkinfo_s { 97 /* Max number of flows (for efficiency) */ 98 int max_flows_rx; 99 int max_flows_tx; 100 101 /* seqnum history slice pools */ 102 tsn_sr_seqnum_slice_t *sn_pools[TSN_SRFLOWS_RX_SN_HIST_POOLS] 103 [TSN_SRFLOWS_RX_SNPOOL_SIZE_COUNT]; 104 tsn_sr_seqnum_slice_t *sn_entries_avail; 105 tsn_sr_seqnum_slice_t *sn_entries_allocated; 106 sal_mutex_t snpool_mutex; 107 108 } gh2_tsn_sr_flows_bkinfo_t; 109 110 #endif /* BCM_TSN_SR_SUPPORT */ 111 112 /* Structure definition for GH2 MTU profile memory bookkeeping information */ 113 typedef struct gh2_tsn_mtu_bk_info_s { 114 soc_profile_mem_t *mtu_profile[bcmTsnMtuProfileTypeCount]; 115 sal_mutex_t mutex; 116 } gh2_tsn_mtu_bk_info_t; 117 118 /* Structure definition for GH2 STU profile memory bookkeeping information */ 119 typedef struct gh2_tsn_stu_bk_info_s { 120 soc_profile_mem_t *stu_profile[bcmTsnStuProfileTypeCount]; 121 sal_mutex_t mutex; 122 } gh2_tsn_stu_bk_info_t; 123 124 /* Structure definition for GH2 PRP-forwarding bookkeeping information */ 125 typedef struct gh2_tsn_prp_forwarding_bk_info_s { 126 int prp_forwarding_enable; 127 bcm_field_group_t prp_redirect_group; 128 bcm_port_t prp_redirect_port; 129 bcm_gport_t prp_redirect_gport; 130 int switch_init; 131 sal_mutex_t mutex; 132 } gh2_tsn_prp_forwarding_bk_info_t; 133 134 typedef struct gh2_tsn_events_bkinfo_s { 135 bcmi_esw_tsn_flow_event_notify_cb gh2_flow_event_notify; 136 bcmi_esw_tsn_cnt_exceed_notify_cb gh2_cnt_exceed_notify; 137 sal_mutex_t event_mutex; 138 int max_rx_flows; 139 SHR_BITDCL *active_rx_fbmp; /* Current active rx flows */ 140 int active_rx_fbmp_min; 141 int active_rx_fbmp_max; 142 SHR_BITDCL *wrong_lana_fbmp; /* Watched flows for wrong lan events */ 143 SHR_BITDCL *wrong_lanb_fbmp; /* Watched flows for wrong lan events */ 144 SHR_BITDCL *sn_reset_fbmp; /* Watched flows for sn window reset */ 145 int wrong_lana_min_cd; /* Min count down value of wrong lan a */ 146 int wrong_lanb_min_cd; /* Min count down value of wrong lan b */ 147 int sn_reset_min_cd; /* Min count down value of sn reset */ 148 uint32 window_reset_mode; 149 uint32 ageout_tick_ms; 150 uint32 age_enable; 151 sal_usecs_t ptime; /* previous time */ 152 int wla_tick; 153 int wlb_tick; 154 int reset_tick; 155 int wla_mask; 156 int wlb_mask; 157 } gh2_tsn_events_bkinfo_t; 158 159 /* 160 * TSN flow management: HW platform specific constants 161 */ 162 #define TSN_FLOWS_MAX_NUM_OF_FLOWS 4095 163 164 /* Initialization flag for GH2 TSN bookkeeping info structure */ 165 static int gh2_tsn_bkinfo_initialized = 0; 166 167 /* Structure definition for GH2 TSN bookkeeping info */ 168 typedef struct gh2_tsn_bkinfo_s { 169 gh2_tsn_mtu_bk_info_t gh2_mtu_bk_info; 170 gh2_tsn_stu_bk_info_t gh2_stu_bk_info; 171 gh2_tsn_prp_forwarding_bk_info_t gh2_prp_forwarding_bk_info; 172 #if defined(BCM_TSN_SR_SUPPORT) 173 gh2_tsn_sr_flows_bkinfo_t sr_flows; 174 #endif /* BCM_TSN_SR_SUPPORT */ 175 gh2_tsn_events_bkinfo_t tsn_events; 176 } gh2_tsn_bkinfo_t; 177 178 /* GH2 TSN bookkeeping info */ 179 STATIC gh2_tsn_bkinfo_t *gh2_tsn_bkinfo[BCM_MAX_NUM_UNITS]; 180 181 /* Check if TSN bookkeeping info structure intialized */ 182 #define TSN_BKINFO_IS_INIT(_unit_) \ 183 do { \ 184 if (!SOC_UNIT_VALID(_unit_)) { \ 185 return BCM_E_UNIT; \ 186 } \ 187 if (gh2_tsn_bkinfo[(_unit_)] == NULL) { \ 188 LOG_ERROR(BSL_LS_BCM_TSN, \ 189 (BSL_META_U((_unit_), \ 190 "TSN Error: chip bookkeeping info not " \ 191 "initialized\n"))); \ 192 return (BCM_E_INIT); \ 193 } \ 194 } while (0) 195 196 /* Function Enter/Leave Tracing */ 197 #define GH2_TSN_FUNCTION_TRACE(_u_, _str_) \ 198 do { \ 199 LOG_DEBUG(BSL_LS_BCM_TSN, \ 200 (BSL_META_U((_u_), \ 201 "%s: " _str_ "\n"), __FUNCTION__)); \ 202 } while (0) 203 204 /* For TSN bookkeeping access */ 205 #define TSN_BKINFO(_u_) gh2_tsn_bkinfo[_u_] 206 207 /* Check if TSN MTU bookkeeping info structure initialized */ 208 #define TSN_MTU_BKINFO_IS_INIT(_unit_, _type_) \ 209 do { \ 210 TSN_BKINFO_IS_INIT(_unit_); \ 211 if ((_type_) != bcmTsnMtuProfileTypeIngress && \ 212 (_type_) != bcmTsnMtuProfileTypeEgress) { \ 213 return BCM_E_PARAM; \ 214 } \ 215 if ((NULL == \ 216 gh2_tsn_bkinfo[(_unit_)]->gh2_mtu_bk_info.mtu_profile[_type_])) { \ 217 LOG_ERROR(BSL_LS_BCM_TSN, \ 218 (BSL_META_U((_unit_), \ 219 "TSN Error: MTU bookkeeping info not " \ 220 "initialized\n"))); \ 221 return BCM_E_INIT; \ 222 } \ 223 } while (0) 224 225 226 /* TSN event management: bookkeeping access */ 227 #define EVENTS_BKINFO(_u_) (&TSN_BKINFO(_u_)->tsn_events) 228 229 /* TSN event management: mutex */ 230 #define EVENT_MGMT_LOCK(_u_) \ 231 sal_mutex_take(EVENTS_BKINFO(unit)->event_mutex, sal_mutex_FOREVER) 232 #define EVENT_MGMT_UNLOCK(_u_) \ 233 sal_mutex_give(EVENTS_BKINFO(unit)->event_mutex) 234 235 /* MTU Bookkeeping Information lock/unlock */ 236 #define MTU_BKINFO_LOCK(_u_) \ 237 sal_mutex_take(gh2_tsn_bkinfo[(_u_)]->gh2_mtu_bk_info.mutex, \ 238 sal_mutex_FOREVER) 239 240 #define MTU_BKINFO_UNLOCK(_u_) \ 241 sal_mutex_give(gh2_tsn_bkinfo[(_u_)]->gh2_mtu_bk_info.mutex) 242 243 /* Check if TSN STU bookkeeping info structure initialized */ 244 #define TSN_STU_BKINFO_IS_INIT(_unit_, _type_) \ 245 do { \ 246 TSN_BKINFO_IS_INIT(_unit_); \ 247 if ((_type_) != bcmTsnStuProfileTypeIngress && \ 248 (_type_) != bcmTsnStuProfileTypeEgress) { \ 249 return BCM_E_PARAM; \ 250 } \ 251 if ((NULL == \ 252 gh2_tsn_bkinfo[(_unit_)]->gh2_stu_bk_info.stu_profile[_type_])) { \ 253 LOG_ERROR(BSL_LS_BCM_TSN, \ 254 (BSL_META_U((_unit_), \ 255 "TSN Error: STU bookkeeping info not " \ 256 "initialized\n"))); \ 257 return BCM_E_INIT; \ 258 } \ 259 } while (0) 260 261 /* STU Bookkeeping Information lock/unlock */ 262 #define STU_BKINFO_LOCK(_u_) \ 263 sal_mutex_take(gh2_tsn_bkinfo[(_u_)]->gh2_stu_bk_info.mutex, \ 264 sal_mutex_FOREVER) 265 266 #define STU_BKINFO_UNLOCK(_u_) \ 267 sal_mutex_give(gh2_tsn_bkinfo[(_u_)]->gh2_stu_bk_info.mutex) 268 269 /* GH2 support 8 internal priority for MTU/STU profile ID */ 270 #define EGRESS_MTU_STU_INT_PRI_NUM 8 271 272 /* Egress MTU & STU profile ID encode value */ 273 #define EGR_MTU_STU_PROFILE_ID_ENCODE 0x01000000 274 275 /* Refer to GH2 EGR_MTU_CHECK/EGR_STU_CHECK (66 ports) */ 276 #define GH2_LOGIC_PORT_MAX_NUM 66 277 278 /* MTU profile memory information */ 279 STATIC const soc_mem_t gh2_mtu_profile_mem[bcmTsnMtuProfileTypeCount] = 280 {MTU_PROFILEm, 281 EGR_MTU_PROFILEm}; 282 /* STU profile memory information */ 283 STATIC const soc_mem_t gh2_stu_profile_mem[bcmTsnStuProfileTypeCount] = 284 {STU_PROFILEm, 285 EGR_STU_PROFILEm}; 286 287 /* 288 * Definitions for Modified-PRP port's custom header(32 bits) 289 * +-------------------------------+ 290 * | Ethertype (16 bits) | 291 * +--------------+----------------+ 292 * | Non_PRP Flag | Port (15 bits) | 293 * +--------------+----------------+ 294 * 295 * Field location : 296 * - Port : b0~b14 297 * - Non_PRP Flag : b15 298 * - Ethertype : b16~b31 299 * 300 * Note : 301 * - Macros defined below for the term of "CH" means "CustomHeader" 302 */ 303 #define PRP_FORWARDING_CH_HEADER_MASK 0xffffffff 304 #define PRP_FORWARDING_CH_ETHERTYPE_MASK 0xffff 305 #define PRP_FORWARDING_CH_ETHERTYPE_OFFSET 16 306 #define PRP_FORWARDING_CH_NON_PRP_OFFSET 15 307 #define PRP_FORWARDING_CH_PORT_MASK 0x7fff 308 #define PRP_FORWARDING_CH_PORT_OFFSET 0 309 310 /* SW defined a non-common value for Modified-PRP(loopback) port */ 311 #define PRP_FORWARDING_CH_ETHERTYPE 0x10bc 312 313 #define PRP_FORWARDING_CH_ENCAP_VALUE(_non_prp_, _port_) \ 314 ((PRP_FORWARDING_CH_ETHERTYPE << PRP_FORWARDING_CH_ETHERTYPE_OFFSET) |\ 315 (((_non_prp_) ? 1 : 0) << PRP_FORWARDING_CH_NON_PRP_OFFSET) | \ 316 (((_port_) & PRP_FORWARDING_CH_PORT_MASK) << \ 317 PRP_FORWARDING_CH_PORT_OFFSET)) 318 319 /* PRP-forwarding Bookkeeping Information lock/unlock */ 320 #define PRP_FORWARDING_BKINFO_LOCK(_u_) \ 321 sal_mutex_take(gh2_tsn_bkinfo[(_u_)]-> \ 322 gh2_prp_forwarding_bk_info.mutex, sal_mutex_FOREVER) 323 324 #define PRP_FORWARDING_BKINFO_UNLOCK(_u_) \ 325 sal_mutex_give(gh2_tsn_bkinfo[(_u_)]-> \ 326 gh2_prp_forwarding_bk_info.mutex) 327 328 #define PRP_FORWARDING_NEED_PRP_SETTING(_config_) \ 329 (((bcmTsnSrPortTypeNone != (_config_).port_type) && \ 330 (bcmTsnSrPortTypePrp == (_config_).port_type || \ 331 bcmTsnSrPortModeInterworkingPrp == (_config_).port_mode)) ? 1 : 0) 332 333 #define PRP_FORWARDING_NEED_EGRESS_MASK_SETTING(_config_) \ 334 ((bcmTsnSrPortTypeNone != (_config_).port_type && \ 335 bcmTsnSrPortTypePrp != (_config_).port_type && \ 336 bcmTsnSrPortTypeDot1cb != (_config_).port_type && \ 337 bcmTsnSrPortModeInterworkingPrp != (_config_).port_mode && \ 338 0 == (_config_).mac_da_flows) ? 1 : 0) 339 340 #define PRP_FORWARDING_REDIRECT_GROUP_INVALID (0) 341 342 #define PRP_FORWARDING_ENABLE(_u_)\ 343 (TSN_BKINFO(_u_)->gh2_prp_forwarding_bk_info.prp_forwarding_enable) 344 #define PRP_FORWARDING_SWITCH_INIT(_u_)\ 345 (TSN_BKINFO(_u_)->gh2_prp_forwarding_bk_info.switch_init) 346 #define PRP_FORWARDING_REDIRECT_GROUP(_u_)\ 347 (TSN_BKINFO(_u_)->gh2_prp_forwarding_bk_info.prp_redirect_group) 348 #define PRP_FORWARDING_REDIRECT_PORT(_u_)\ 349 (TSN_BKINFO(_u_)->gh2_prp_forwarding_bk_info.prp_redirect_port) 350 #define PRP_FORWARDING_REDIRECT_GPORT(_u_)\ 351 (TSN_BKINFO(_u_)->gh2_prp_forwarding_bk_info.prp_redirect_gport) 352 353 #define PRP_FORWARDING_ERROR_RETURN(_op_) \ 354 do { \ 355 int _rv_ = (_op_); \ 356 if (BCM_FAILURE(_rv_)) { \ 357 return (_rv_); \ 358 } \ 359 } while (0) 360 361 #define PRP_FORWARDING_ERROR_RETURN_WITH_CLEAN(_op_, _extra_clean_) \ 362 do { \ 363 int _rv_ = (_op_); \ 364 if (BCM_FAILURE(_rv_)) { \ 365 (_extra_clean_); \ 366 return (_rv_); \ 367 } \ 368 } while (0) 369 370 #define PRP_FORWARDING_CLEAN_ERROR_RETURN(_op_) \ 371 do { \ 372 int _rv_ = (_op_); \ 373 if (BCM_FAILURE(_rv_)) { \ 374 LOG_WARN(BSL_LS_BCMAPI_TSN, \ 375 (BSL_META_U( \ 376 unit, \ 377 "prp_forwarding clean failed\n"))); \ 378 return; \ 379 } \ 380 } while (0) 381 382 #define PRP_FORWARDING_CREATE_ERROR_RETURN(_op_) \ 383 do { \ 384 int _rv_ = (_op_); \ 385 if (BCM_FAILURE(_rv_)) { \ 386 bcmi_gh2_tsn_sr_port_prp_forwarding_destroy(unit, prp_port); \ 387 return (_rv_); \ 388 } \ 389 } while (0) 390 391 #define PRP_FORWARDING_DESTROY_ERROR_RETURN(_op_) \ 392 do { \ 393 int _rv_ = (_op_); \ 394 if (BCM_FAILURE(_rv_)) { \ 395 LOG_WARN(BSL_LS_BCMAPI_TSN, \ 396 (BSL_META_U( \ 397 unit, \ 398 "prp_forwarding destroy port %d failed\n"), \ 399 prp_port)); \ 400 return; \ 401 } \ 402 } while (0) 403 404 #define PRP_FORWARDING_DESTROY_ERROR_RETURN_WITH_CLEAN(_op_, _extra_clean_) \ 405 do { \ 406 int _rv_ = (_op_); \ 407 if (BCM_FAILURE(_rv_)) { \ 408 (_extra_clean_); \ 409 LOG_WARN(BSL_LS_BCMAPI_TSN, \ 410 (BSL_META_U( \ 411 unit, \ 412 "prp_forwarding destroy port %d failed\n"), \ 413 prp_port)); \ 414 return; \ 415 } \ 416 } while (0) 417 418 #if defined(BCM_TSN_SR_SUPPORT) 419 420 /* SR flow management: quick array to get power of 2 */ 421 static const int tsn_math_powers[] = { 422 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 423 8192, 16384, 32768, 65536 424 }; 425 426 /* SR flow management: SR RX flow seqnum history field names */ 427 static const soc_field_t tsn_flow_sr_hist_indexs[] = { 428 SN_HISTORY_INDEX_1f, SN_HISTORY_INDEX_2f, 429 SN_HISTORY_INDEX_3f, SN_HISTORY_INDEX_4f 430 }; 431 static const soc_field_t tsn_flow_sr_hist_offsets[] = { 432 SN_HISTORY_OFFSET_1f, SN_HISTORY_OFFSET_2f, 433 SN_HISTORY_OFFSET_3f, SN_HISTORY_OFFSET_4f 434 }; 435 static const soc_field_t tsn_flow_sr_hist_sizes[] = { 436 SN_HISTORY_SIZE_1f, SN_HISTORY_SIZE_2f, 437 SN_HISTORY_SIZE_3f, SN_HISTORY_SIZE_4f 438 }; 439 440 /* SR flow management: SR RX seqnum history pool table names */ 441 static const soc_mem_t tsn_flow_sr_hist_pools[] = { 442 SR_SN_HISTORY_0m, 443 SR_SN_HISTORY_1m, 444 SR_SN_HISTORY_2m, 445 SR_SN_HISTORY_3m, 446 SR_SN_HISTORY_4m, 447 SR_SN_HISTORY_5m, 448 SR_SN_HISTORY_6m, 449 SR_SN_HISTORY_7m, 450 SR_SN_HISTORY_8m, 451 SR_SN_HISTORY_9m, 452 SR_SN_HISTORY_10m, 453 SR_SN_HISTORY_11m, 454 SR_SN_HISTORY_12m, 455 SR_SN_HISTORY_13m, 456 SR_SN_HISTORY_14m, 457 SR_SN_HISTORY_15m 458 }; 459 460 /* SR flow management: helper macros for flow ID conversion */ 461 #define TSN_SRFLOWS_IDX_TO_HW_ID(_tx_, _idx_) \ 462 (((_idx_) + 1) | ((_tx_) ? TSN_SRFLOWS_FLOWID_TX_MASK : 0)) 463 #define TSN_SRFLOWS_HW_ID_IS_TX(_id_) \ 464 (((_id_) & TSN_SRFLOWS_FLOWID_TX_MASK) ? 1 : 0) 465 #define TSN_SRFLOWS_HW_ID_TO_IDX(_id_) \ 466 (((_id_) & (~TSN_SRFLOWS_FLOWID_TX_MASK)) - 1) 467 468 /* SR flow management: bookkeeping access (for easier porting) */ 469 #define SRFLOWS_BKINFO(_u_) (TSN_BKINFO(_u_)->sr_flows) 470 471 /* SR flow management: convenient macro for seqnum pool protecting */ 472 #define SRFLOWS_SNPOOL_LOCK(_u_) \ 473 sal_mutex_take(SRFLOWS_BKINFO(unit).snpool_mutex, sal_mutex_FOREVER) 474 #define SRFLOWS_SNPOOL_UNLOCK(_u_) \ 475 sal_mutex_give(SRFLOWS_BKINFO(unit).snpool_mutex) 476 477 /* SR flow management: convenient macro to access seqnum slice pools */ 478 #define SR_SNPOOL(_idx, _pow) SRFLOWS_BKINFO(unit).sn_pools[_idx][_pow] 479 480 /* SR flow management: helper macro to get a slice from pool */ 481 #define TSN_SRFLOW_GET_SN_SLICE(_sn, _idx, _pow) \ 482 do { \ 483 (_sn) = SR_SNPOOL((_idx), (_pow)); \ 484 if ((_sn) != NULL) { \ 485 SR_SNPOOL((_idx), (_pow)) = (_sn)->next; \ 486 (_sn)->next = NULL; \ 487 } \ 488 } while (0) 489 490 /* Convenient macro: check whether a number is power of 2 */ 491 #define TSN_IS_POWER_OF_2(_n_) (!((_n_) & ((_n_) - 1))) 492 493 /* Convenient macro: get log2 for a non-zero power-of-2 number */ 494 #define TSN_GET_LOG2(_n_, _power_) \ 495 do { \ 496 unsigned int _num = (unsigned int)(_n_); \ 497 for ((_power_) = -1; _num; (_power_)++) { \ 498 _num >>= 1; \ 499 } \ 500 } while (0) 501 502 /* 503 * SR Auto Learn : 504 * flow ID is 13-bit (1st lead bit is global for TX and RX) 505 * Doing 12-bit mask for NEXT_FLOW_ID 506 */ 507 #define AUTO_LEARN_FLOW_ID_TO_HW_FLOW_ID(_idx_) \ 508 ((_idx_) & 0x0FFF) 509 #define AUTO_LEARN_HW_FLOW_ID_TO_FLOW_ID(_type_, _idx_) \ 510 (((_type_) == bcmi_sr_auto_learn_flow_tx ? 0x1000 : 0x0) | \ 511 ((_idx_) & 0x0FFF)) 512 513 #endif /* BCM_TSN_SR_SUPPORT */ 514 515 /* TSN flow management: helper macros for flow ID conversion */ 516 #define TSN_FLOWS_IDX_TO_HW_ID(_idx_) ((_idx_) + 1) 517 #define TSN_FLOWS_HW_ID_TO_IDX(_id_) ((_id_) - 1) 518 519 STATIC int 520 bcmi_gh2_tsn_mtu_profile_decode( 521 int unit, 522 int mtu_profile_id, 523 bcm_tsn_mtu_profile_type_t *type, 524 int *index); 525 526 STATIC int 527 bcmi_gh2_tsn_mtu_profile_encode( 528 int unit, 529 int index, 530 bcm_tsn_mtu_profile_type_t type, 531 int *mtu_profile_id); 532 533 #if defined(BCM_TSN_SR_SUPPORT) 534 535 /* SR flow mgmt - free seqnum history pool */ 536 STATIC int 537 bcmi_gh2_tsn_sr_flows_seqnum_slice_free( 538 int unit, 539 bcmi_tsn_sr_seqnum_slice_t slice) 540 { 541 tsn_sr_seqnum_slice_t *org = (tsn_sr_seqnum_slice_t *)slice; 542 tsn_sr_seqnum_slice_t *sn, *sn2, *prev; 543 int entries; 544 int pow; 545 int offset; 546 int merged; 547 int i; 548 549 /* parameter check */ 550 TSN_BKINFO_IS_INIT(unit); 551 if (!soc_feature(unit, soc_feature_tsn_sr)) { 552 return (BCM_E_UNAVAIL); 553 } 554 if (NULL == slice) { 555 return BCM_E_PARAM; 556 } 557 558 /* validate it first before putting back into the pools */ 559 i = 0; 560 entries = soc_mem_index_count(unit, SR_SN_HISTORY_0m); 561 for (sn = org; sn != NULL; sn = sn->next) { 562 /* The total number of chained slices < number of pools */ 563 i++; 564 if (i > TSN_SRFLOWS_RX_SN_HIST_POOLS) { 565 return BCM_E_PARAM; 566 } 567 568 /* Validate item values */ 569 if (sn->index < 0 || sn->index >= TSN_SRFLOWS_RX_SN_HIST_POOLS) { 570 return BCM_E_PARAM; 571 } 572 if (sn->power < TSN_SRFLOWS_RX_SNPOOL_POWER_MIN || 573 sn->power > TSN_SRFLOWS_RX_SNPOOL_POWER_MAX) { 574 return BCM_E_PARAM; 575 } 576 if (sn->offset < 0 || sn->offset >= TSN_SRFLOWS_RX_SNPOOL_SIZE_MAX) { 577 return BCM_E_PARAM; 578 } 579 if (sn->offset % tsn_math_powers[sn->power]) { 580 /* offset should be multiples of the slice size */ 581 return BCM_E_PARAM; 582 } 583 if (sn->entry < 0 || sn->entry >= entries) { 584 return BCM_E_PARAM; 585 } 586 } 587 588 /* Put back to the pools one by one */ 589 while (org != NULL) { 590 /* Handle one slice at a time */ 591 sn = org; 592 org = sn->next; 593 sn->next = NULL; 594 595 /* Start putting back the slice */ 596 SRFLOWS_SNPOOL_LOCK(unit); 597 598 /* See if we can find another half and merge into a bigger one */ 599 pow = sn->power - TSN_SRFLOWS_RX_SNPOOL_POWER_MIN; 600 for (i = pow; i < TSN_SRFLOWS_RX_SNPOOL_IDX_MAX; i++) { 601 /* 602 * Calculate the offset value for the slice of another half 603 * Another offset = this_offset XOR slice_size 604 * (offset must be multiples of the slice_size) 605 */ 606 offset = sn->offset ^ tsn_math_powers[sn->power]; 607 608 /* Find the slice with the offset within the same entry */ 609 merged = 0; 610 prev = NULL; 611 for (sn2 = SR_SNPOOL(sn->index, i); sn2 != NULL; sn2 = sn2->next) { 612 if (sn2->offset == offset) { 613 if (sn2->entry == sn->entry) { 614 615 /* Found. Remove it from the pool */ 616 if (prev == NULL) { 617 SR_SNPOOL(sn->index, i) = sn2->next; 618 } else { 619 prev->next = sn2->next; 620 } 621 622 /* Change it to be next size with offset corrected */ 623 sn2->power++; 624 sn2->offset &= ~tsn_math_powers[sn->power]; 625 sn2->next = NULL; 626 627 /* Free the original one */ 628 sn->next = SRFLOWS_BKINFO(unit).sn_entries_avail; 629 SRFLOWS_BKINFO(unit).sn_entries_avail = sn; 630 631 /* This becomes the one to return to the pool */ 632 sn = sn2; 633 pow = sn2->power - TSN_SRFLOWS_RX_SNPOOL_POWER_MIN; 634 merged = 1; 635 break; 636 } 637 } 638 prev = sn2; 639 } 640 /* 641 * If no merge happens, just return it to the pool. 642 * Otherwise try to merge in the next size level. 643 */ 644 if (!merged) { 645 break; 646 } 647 } 648 649 /* Return the slice to the pool */ 650 sn->next = SR_SNPOOL(sn->index, pow); 651 SR_SNPOOL(sn->index, pow) = sn; 652 653 /* Done this one */ 654 SRFLOWS_SNPOOL_UNLOCK(unit); 655 } 656 657 return BCM_E_NONE; 658 } 659 660 /* SR flow mgmt - allocate seqnum history pool */ 661 STATIC int 662 bcmi_gh2_tsn_sr_flows_seqnum_slice_alloc( 663 int unit, 664 int winsize, 665 bcmi_tsn_sr_seqnum_slice_t *slice) 666 { 667 tsn_sr_seqnum_slice_t *sn, *sn2, *sn3, *sn4; 668 int power, pow; 669 int i, j, k, m; 670 671 /* For convenience */ 672 static const int num_pools = TSN_SRFLOWS_RX_SN_HIST_POOLS; 673 674 /* parameter check */ 675 TSN_BKINFO_IS_INIT(unit); 676 if (!soc_feature(unit, soc_feature_tsn_sr)) { 677 return (BCM_E_UNAVAIL); 678 } 679 if (NULL == slice || winsize <= 0 || !TSN_IS_POWER_OF_2(winsize)) { 680 return BCM_E_PARAM; 681 } 682 683 /* Validate and correct size */ 684 TSN_GET_LOG2(winsize, power); 685 if (power == 0) { 686 /* Special case: use 64-bit slice for 1-bit window size */ 687 power = TSN_SRFLOWS_RX_WINDOW_POWER_MIN; 688 } 689 if (power < TSN_SRFLOWS_RX_WINDOW_POWER_MIN || 690 power > TSN_SRFLOWS_RX_WINDOW_POWER_MAX) { 691 return BCM_E_PARAM; 692 } 693 pow = power - TSN_SRFLOWS_RX_WINDOW_POWER_MIN; /* pool slot index */ 694 695 /* Start finding matching slices */ 696 SRFLOWS_SNPOOL_LOCK(unit); 697 698 /* 699 * 1. Check for exact match 700 * Only applies when the window size is one of the slice size 701 */ 702 if (pow <= TSN_SRFLOWS_RX_SNPOOL_IDX_MAX) { 703 for (i = 0; i < num_pools; i++) { 704 if (SR_SNPOOL(i, pow) != NULL) { 705 /* Got one exact match slice */ 706 TSN_SRFLOW_GET_SN_SLICE(sn, i, pow); 707 *slice = (bcmi_tsn_sr_seqnum_slice_t)sn; 708 SRFLOWS_SNPOOL_UNLOCK(unit); 709 return BCM_E_NONE; 710 } 711 } 712 } 713 714 /* 715 * 2. Check if the following conditions can meet 716 * - 1/2 + 1/2 717 * - 1/2 + 1/4 + 1/4 718 * - 1/2 + 1/4 + 1/8 + 1/8 719 * This only applies to 720 * - numbers that can be broken down to half (so power >= 1) 721 * - numbers that are at most twice of the max slice size 722 * (so pow <= TSN_SRFLOWS_RX_SNPOOL_IDX_MAX + 1) 723 */ 724 if (pow >= 1 && pow <= TSN_SRFLOWS_RX_SNPOOL_IDX_MAX + 1) { 725 /* Find the first 1/2 slice */ 726 for (i = 0; i < num_pools; i++) { 727 if (SR_SNPOOL(i, pow - 1) != NULL) { 728 /* Found the first 1/2 slice, now find the 2nd 1/2 slice */ 729 for (j = 0; j < num_pools; j++) { 730 if (j == i) { 731 continue; 732 } 733 if (SR_SNPOOL(j, pow - 1) != NULL) { 734 /* Found 1/2 + 1/2 slice, chain and return */ 735 TSN_SRFLOW_GET_SN_SLICE(sn, i, pow - 1); 736 assert(sn != NULL); 737 TSN_SRFLOW_GET_SN_SLICE(sn2, j, pow - 1); 738 sn->next = sn2; 739 *slice = (bcmi_tsn_sr_seqnum_slice_t)sn; 740 SRFLOWS_SNPOOL_UNLOCK(unit); 741 return BCM_E_NONE; 742 } 743 } 744 745 /* Only one 1/2 slice available, so try to find 1/4 slices */ 746 if (pow >= 2) { 747 for (j = 0; j < num_pools; j++) { 748 if (j == i) { 749 continue; 750 } 751 if (SR_SNPOOL(j, pow - 2) != NULL) { 752 /* Found first 1/4, now find another 1/4 slice */ 753 for (k = 0; k < num_pools; k++) { 754 if (k == i || k == j) { 755 continue; 756 } 757 if (SR_SNPOOL(k, pow - 2) != NULL) { 758 /* Found 1/2 + 1/4 + 1/4 */ 759 TSN_SRFLOW_GET_SN_SLICE(sn, i, pow - 1); 760 assert(sn != NULL); 761 TSN_SRFLOW_GET_SN_SLICE(sn2, j, pow - 2); 762 assert(sn2 != NULL); 763 TSN_SRFLOW_GET_SN_SLICE(sn3, k, pow - 2); 764 sn2->next = sn3; 765 sn->next = sn2; 766 *slice = (bcmi_tsn_sr_seqnum_slice_t)sn; 767 SRFLOWS_SNPOOL_UNLOCK(unit); 768 return BCM_E_NONE; 769 } 770 } 771 772 /* Try to find remaining 1/8 + 1/8 */ 773 if (pow >= 3) { 774 m = -1; 775 for (k = 0; k < num_pools; k++) { 776 if (k == i || k == j) { 777 continue; 778 } 779 if (SR_SNPOOL(k, pow - 3) != NULL) { 780 if (m == -1) { 781 /* Found first 1/8, record it */ 782 m = k; 783 } else { 784 /* Found 1/2 + 1/4 + 1/8 x 2 */ 785 TSN_SRFLOW_GET_SN_SLICE( 786 sn, i, pow - 1); 787 assert(sn != NULL); 788 TSN_SRFLOW_GET_SN_SLICE( 789 sn2, j, pow - 2); 790 assert(sn2 != NULL); 791 TSN_SRFLOW_GET_SN_SLICE( 792 sn3, m, pow - 3); 793 assert(sn3 != NULL); 794 TSN_SRFLOW_GET_SN_SLICE( 795 sn4, k, pow - 3); 796 sn3->next = sn4; 797 sn2->next = sn3; 798 sn->next = sn2; 799 *slice = 800 (bcmi_tsn_sr_seqnum_slice_t)sn; 801 SRFLOWS_SNPOOL_UNLOCK(unit); 802 return BCM_E_NONE; 803 } 804 } 805 } 806 } 807 } 808 } 809 } 810 } 811 } 812 } 813 814 /* 815 * 3. Check if we can find 1/4 + 1/4 + 1/4 + 1/4 816 * - numbers that can be broken down to 1/4 (so power >= 2) 817 * - numbers that are at most 4 times of the max slice size 818 * (so pow <= TSN_SRFLOWS_RX_SNPOOL_IDX_MAX + 2) 819 * Note this algorithm is optimized for 4 pools. 820 */ 821 if (pow >= 2 && pow <= TSN_SRFLOWS_RX_SNPOOL_IDX_MAX + 2) { 822 /* Check if all pools have 1/4 slices */ 823 for (i = 0; i < num_pools; i++) { 824 if (SR_SNPOOL(i, pow - 2) == NULL) { 825 break; 826 } 827 } 828 if (i == num_pools) { 829 /* All pools has 1/4 slices, chain them and return */ 830 sn = NULL; 831 for (j = 0; j < num_pools; j++) { 832 TSN_SRFLOW_GET_SN_SLICE(sn2, j, pow - 2); 833 assert(sn2 != NULL); 834 if (sn == NULL) { 835 sn = sn2; 836 } else { 837 sn2->next = sn; 838 sn = sn2; 839 } 840 } 841 *slice = (bcmi_tsn_sr_seqnum_slice_t)sn; 842 SRFLOWS_SNPOOL_UNLOCK(unit); 843 return BCM_E_NONE; 844 } 845 } 846 847 /* 848 * 4. Cannot find smaller slices for combining. 849 * Try to break down bigger slices for it. 850 */ 851 if (pow >= TSN_SRFLOWS_RX_SNPOOL_IDX_MAX) { 852 /* No bigger slice than this */ 853 SRFLOWS_SNPOOL_UNLOCK(unit); 854 return BCM_E_RESOURCE; 855 } 856 /* Find bigger slices to break, starting from next size */ 857 for (m = pow + 1; m <= TSN_SRFLOWS_RX_SNPOOL_IDX_MAX; m++) { 858 /* Scan through all pools for this size */ 859 for (i = 0; i < num_pools; i++) { 860 if (SR_SNPOOL(i, m) != NULL) { 861 /* break it until we get the required size */ 862 for (j = m; j > pow; j--) { 863 864 /* Take this one out of the pool */ 865 sn = SR_SNPOOL(i, j); 866 assert(sn != NULL); 867 SR_SNPOOL(i, j) = sn->next; 868 869 /* Break size into half */ 870 sn->power--; 871 872 /* Get another slice instance */ 873 sn2 = SRFLOWS_BKINFO(unit).sn_entries_avail; 874 if (sn2 == NULL) { 875 assert(0); /* shouldn't happen as we allocated max */ 876 SRFLOWS_SNPOOL_UNLOCK(unit); 877 return BCM_E_RESOURCE; 878 } 879 SRFLOWS_BKINFO(unit).sn_entries_avail = sn2->next; 880 881 /* Fill the new slice */ 882 sn2->index = sn->index; 883 sn2->entry = sn->entry; 884 sn2->power = sn->power; 885 sn2->next = NULL; 886 887 /* Calculate new offset */ 888 assert(sn->power < sizeof(tsn_math_powers) / sizeof(int)); 889 sn2->offset = sn->offset + tsn_math_powers[sn->power]; 890 891 /* Chain them together */ 892 sn->next = sn2; 893 894 /* Put into the pool of the new size */ 895 sn2->next = SR_SNPOOL(i, j - 1); 896 SR_SNPOOL(i, j - 1) = sn; 897 } 898 899 /* Now we should have available slices */ 900 sn = SR_SNPOOL(i, pow); 901 assert(sn != NULL); 902 SR_SNPOOL(i, pow) = sn->next; 903 sn->next = NULL; 904 *slice = (bcmi_tsn_sr_seqnum_slice_t)sn; 905 SRFLOWS_SNPOOL_UNLOCK(unit); 906 return BCM_E_NONE; 907 } 908 } 909 } 910 911 /* Cannot find slices to fulfill the request */ 912 SRFLOWS_SNPOOL_UNLOCK(unit); 913 return BCM_E_RESOURCE; 914 } 915 916 #ifdef BCM_WARM_BOOT_SUPPORT 917 /* SR flow mgmt - break slice until specified slice found (called with lock) */ 918 STATIC int 919 bcmi_gh2_tsn_sr_flows_seqnum_slice_wb_break( 920 int unit, 921 tsn_sr_seqnum_slice_t *slice, 922 int offset, 923 int power, 924 tsn_sr_seqnum_slice_t **pslice) 925 { 926 tsn_sr_seqnum_slice_t *sn, *sn2, *sn_break, *sn_put; 927 int diff; 928 int pow; 929 930 /* parameter check */ 931 TSN_BKINFO_IS_INIT(unit); 932 if (!soc_feature(unit, soc_feature_tsn_sr)) { 933 return (BCM_E_UNAVAIL); 934 } 935 if (slice == NULL || pslice == NULL || 936 offset < 0 || offset >= TSN_SRFLOWS_RX_SNPOOL_SIZE_MAX || 937 power < TSN_SRFLOWS_RX_SNPOOL_POWER_MIN || 938 power > TSN_SRFLOWS_RX_SNPOOL_POWER_MAX) { 939 return BCM_E_PARAM; 940 } 941 942 /* This routine is for warm boot only */ 943 if (!SOC_WARM_BOOT(unit)) { 944 return BCM_E_UNAVAIL; 945 } 946 947 /* Validate supplied slice supplied by internal caller */ 948 assert(slice->entry >= 0); 949 assert(slice->entry < (uint32)soc_mem_index_count(unit, SR_SN_HISTORY_0m)); 950 assert(slice->offset >= 0); 951 assert(slice->offset < TSN_SRFLOWS_RX_SN_HIST_POOL_SIZE); 952 assert(slice->power >= TSN_SRFLOWS_RX_SNPOOL_POWER_MIN); 953 assert(slice->power <= TSN_SRFLOWS_RX_SNPOOL_POWER_MAX); 954 assert(slice->power > power); 955 956 /* break it until we get the specified slice */ 957 sn = slice; 958 for (;;) { 959 960 /* Break size into half */ 961 sn->power--; 962 assert(sn->power >= power); 963 964 /* Get another slice instance */ 965 sn2 = SRFLOWS_BKINFO(unit).sn_entries_avail; 966 if (sn2 == NULL) { 967 assert(0); /* shouldn't happen as we allocated max */ 968 SRFLOWS_SNPOOL_UNLOCK(unit); 969 return BCM_E_RESOURCE; 970 } 971 SRFLOWS_BKINFO(unit).sn_entries_avail = sn2->next; 972 973 /* Fill the new slice */ 974 sn2->index = sn->index; 975 sn2->entry = sn->entry; 976 sn2->power = sn->power; 977 sn2->next = NULL; 978 979 /* Calculate new offset */ 980 assert(sn->power < sizeof(tsn_math_powers) / sizeof(int)); 981 diff = tsn_math_powers[sn->power]; 982 sn2->offset = sn->offset + diff; 983 984 /* Check which one to break and which one to put back */ 985 if (offset & diff) { 986 sn_break = sn2; 987 sn_put = sn; 988 } else { 989 sn_break = sn; 990 sn_put = sn2; 991 } 992 993 /* Put back unused slice into the pool */ 994 pow = sn->power - TSN_SRFLOWS_RX_WINDOW_POWER_MIN; 995 sn_put->next = SR_SNPOOL(sn->index, pow); 996 SR_SNPOOL(sn->index, pow) = sn_put; 997 998 /* Return if we have found it */ 999 if (sn_break->power == power) { 1000 assert(sn_break->offset == offset); 1001 *pslice = sn_break; 1002 break; 1003 } 1004 1005 /* Not yet, break it further */ 1006 sn = sn_break; 1007 } 1008 1009 return BCM_E_NONE; 1010 } 1011 1012 /* SR flow mgmt - get specified SN slice from the pools */ 1013 STATIC int 1014 bcmi_gh2_tsn_sr_flows_seqnum_slice_wb_restore( 1015 int unit, 1016 int index, 1017 int entry, 1018 int offset, 1019 int power, 1020 tsn_sr_seqnum_slice_t **pslice) 1021 { 1022 tsn_sr_seqnum_slice_t *sn, *prev; 1023 int offset2; 1024 int power2; 1025 int pow; 1026 int m; 1027 int rv; 1028 1029 /* parameter check */ 1030 TSN_BKINFO_IS_INIT(unit); 1031 if (!soc_feature(unit, soc_feature_tsn_sr)) { 1032 return (BCM_E_UNAVAIL); 1033 } 1034 if (pslice == NULL || 1035 index < 0 || index >= TSN_SRFLOWS_RX_SN_HIST_POOLS || 1036 entry < 0 || 1037 entry >= (uint32)soc_mem_index_count(unit, SR_SN_HISTORY_0m) || 1038 offset < 0 || offset >= TSN_SRFLOWS_RX_SNPOOL_SIZE_MAX || 1039 power < TSN_SRFLOWS_RX_SNPOOL_POWER_MIN || 1040 power > TSN_SRFLOWS_RX_SNPOOL_POWER_MAX) { 1041 return BCM_E_PARAM; 1042 } 1043 1044 /* This routine is for warm boot only */ 1045 if (!SOC_WARM_BOOT(unit)) { 1046 return BCM_E_UNAVAIL; 1047 } 1048 1049 /* Start finding the specified slice */ 1050 pow = power - TSN_SRFLOWS_RX_WINDOW_POWER_MIN; /* pool slot index */ 1051 SRFLOWS_SNPOOL_LOCK(unit); 1052 1053 /* Check if the exact slice exists */ 1054 prev = NULL; 1055 for (sn = SR_SNPOOL(index, pow); sn != NULL; prev = sn, sn = sn->next) { 1056 if (sn->entry == entry && sn->offset == offset) { 1057 if (prev == NULL) { 1058 SR_SNPOOL(index, pow) = sn->next; 1059 } else { 1060 prev->next = sn->next; 1061 } 1062 *pslice = sn; 1063 SRFLOWS_SNPOOL_UNLOCK(unit); 1064 return BCM_E_NONE; 1065 } 1066 } 1067 1068 /* Need to break down bigger slice to get what we want */ 1069 if (pow >= TSN_SRFLOWS_RX_SNPOOL_IDX_MAX) { 1070 /* No bigger slice than this */ 1071 SRFLOWS_SNPOOL_UNLOCK(unit); 1072 return BCM_E_INTERNAL; 1073 } 1074 /* Find bigger slices to break, starting from next size */ 1075 for (m = pow + 1; m <= TSN_SRFLOWS_RX_SNPOOL_IDX_MAX; m++) { 1076 /* Find the slice containing the specified window */ 1077 if (SR_SNPOOL(index, m) != NULL) { 1078 power2 = m + TSN_SRFLOWS_RX_WINDOW_POWER_MIN; 1079 offset2 = offset & (~(tsn_math_powers[power2] - 1)); 1080 prev = NULL; 1081 for (sn = SR_SNPOOL(index, m); sn != NULL; sn = sn->next) { 1082 if (sn->entry == entry && sn->offset == offset2) { 1083 if (prev == NULL) { 1084 SR_SNPOOL(index, m) = sn->next; 1085 } else { 1086 prev->next = sn->next; 1087 } 1088 rv = bcmi_gh2_tsn_sr_flows_seqnum_slice_wb_break( 1089 unit, sn, offset, power, pslice); 1090 SRFLOWS_SNPOOL_UNLOCK(unit); 1091 return rv; 1092 } 1093 prev = sn; 1094 } 1095 } 1096 } 1097 1098 SRFLOWS_SNPOOL_UNLOCK(unit); 1099 return BCM_E_RESOURCE; 1100 } 1101 #endif /* BCM_WARM_BOOT_SUPPORT */ 1102 1103 /* SR flow mgmt - read seqnum history pool for a flow */ 1104 STATIC int 1105 bcmi_gh2_tsn_sr_flows_seqnum_hist_read( 1106 int unit, 1107 int idx, 1108 int winsize, 1109 bcmi_tsn_sr_seqnum_slice_t slice, 1110 int offset, 1111 int max_size, 1112 uint8 *history, 1113 int *actual) 1114 { 1115 tsn_sr_seqnum_slice_t *sn, *slices[TSN_SRFLOWS_RX_SN_HIST_POOLS]; 1116 int left; /* bits left to read */ 1117 int off; /* current offset to read for this flow */ 1118 int pos; /* starting position within the flow for a slice */ 1119 int sz; /* size of the slice */ 1120 int poff; /* current offset within a pool */ 1121 int pbits; /* bits to read within a pool */ 1122 int sidx; /* sub pool (per memory access) index */ 1123 int soff; /* current offset within a sub pool */ 1124 int sbits; /* bits to read within a sub pool */ 1125 int boff; /* buffer offset in bits */ 1126 soc_mem_t mem; 1127 sr_sn_history_0_entry_t hist_entry; 1128 uint32 fldbuf[TSN_SRFLOWS_RX_SN_HIST_MEM_SIZE / sizeof(uint32)]; 1129 int rv; 1130 int i, j; 1131 1132 /* parameter check */ 1133 TSN_BKINFO_IS_INIT(unit); 1134 if (!soc_feature(unit, soc_feature_tsn_sr)) { 1135 return (BCM_E_UNAVAIL); 1136 } 1137 if (NULL == history || NULL == slice || 1138 idx < 0 || idx >= SRFLOWS_BKINFO(unit).max_flows_rx || 1139 (winsize < TSN_SRFLOWS_RX_WINDOW_SIZE_MIN && winsize != 1) || 1140 winsize > TSN_SRFLOWS_RX_WINDOW_SIZE_MAX) { 1141 return BCM_E_PARAM; 1142 } 1143 1144 /* Put slice in the order of pool index and validate */ 1145 for (i = 0; i < TSN_SRFLOWS_RX_SN_HIST_POOLS; i++) { 1146 slices[i] = NULL; 1147 } 1148 pos = 0; 1149 for (sn = (tsn_sr_seqnum_slice_t *)slice; sn != NULL; sn = sn->next) { 1150 if (sn->index < 0 || sn->index >= TSN_SRFLOWS_RX_SN_HIST_POOLS) { 1151 return BCM_E_PARAM; 1152 } 1153 if (slices[sn->index] != NULL) { 1154 return BCM_E_PARAM; 1155 } 1156 slices[sn->index] = sn; 1157 if (sn->power < TSN_SRFLOWS_RX_SNPOOL_POWER_MIN || 1158 sn->power > TSN_SRFLOWS_RX_SNPOOL_POWER_MAX) { 1159 return BCM_E_PARAM; 1160 } 1161 pos += tsn_math_powers[sn->power]; 1162 } 1163 if (pos != winsize) { 1164 if (pos != TSN_SRFLOWS_RX_SNPOOL_SIZE_MIN || winsize != 1) { 1165 /* The only case that pos != winsize is that winsize = 1 */ 1166 return BCM_E_PARAM; 1167 } 1168 } 1169 1170 /* Calculate bits to read */ 1171 max_size = (max_size > (winsize - offset)) ? (winsize - offset) : max_size; 1172 1173 /* Try to read it pool by pool */ 1174 off = offset; /* Offset of this flow */ 1175 left = max_size; /* Remaining bits to read */ 1176 pos = 0; /* Slice starting position of this flow */ 1177 boff = 0; /* Buffer offset */ 1178 for (i = 0; i < TSN_SRFLOWS_RX_SN_HIST_POOLS; i++) { 1179 if (slices[i] == NULL) { 1180 continue; 1181 } 1182 sn = slices[i]; 1183 sz = tsn_math_powers[sn->power]; /* Size of this slice */ 1184 1185 /* Check if our target is within this slice */ 1186 if (off < pos || off >= pos + sz) { 1187 pos += sz; 1188 continue; 1189 } 1190 1191 /* Calculate starting offset within this pool */ 1192 poff = sn->offset + (off - pos); 1193 1194 /* Calculate bits to read within this pool */ 1195 pbits = sz - (off - pos); 1196 pbits = (pbits > left) ? left : pbits; 1197 1198 /* Loop through sub pools */ 1199 for (j = 0; pbits > 0 && j < TSN_SRFLOWS_RX_SN_HIST_SUB_POOLS; j++) { 1200 /* Check if we need to read this sub pool */ 1201 if (poff < j * TSN_SRFLOWS_RX_SN_HIST_MEM_SIZE || 1202 poff >= (j + 1) * TSN_SRFLOWS_RX_SN_HIST_MEM_SIZE) { 1203 continue; 1204 } 1205 1206 /* Calculate actual HW sub pool index */ 1207 sidx = (i << TSN_SRFLOWS_RX_SN_HIST_SUB_INDEX) | 1208 (poff >> TSN_SRFLOWS_RX_SN_HIST_MEM_POWER); 1209 1210 /* Read the entry and the field from the sub pool */ 1211 assert(sidx < sizeof(tsn_flow_sr_hist_pools) / sizeof(soc_mem_t)); 1212 mem = tsn_flow_sr_hist_pools[sidx]; 1213 sal_memset(&hist_entry, 0, sizeof(hist_entry)); 1214 rv = soc_mem_read(unit, mem, MEM_BLOCK_ANY, sn->entry, &hist_entry); 1215 if (SOC_FAILURE(rv)) { 1216 LOG_ERROR(BSL_LS_BCM_TSN, 1217 (BSL_META_U(unit, "Failed to read mem[%s]"), 1218 SOC_MEM_NAME(unit, mem))); 1219 return rv; 1220 } 1221 soc_mem_field_get( 1222 unit, mem, (uint32 *)&hist_entry, SN_WINDOWf, fldbuf); 1223 1224 /* Calculate starting offset within this sub pool */ 1225 soff = poff & (TSN_SRFLOWS_RX_SN_HIST_MEM_SIZE - 1); 1226 1227 /* Calculate bits to read within this sub pool */ 1228 sbits = TSN_SRFLOWS_RX_SN_HIST_MEM_SIZE - soff; 1229 sbits = (sbits > pbits) ? pbits : sbits; 1230 1231 /* Copy bits from field to buffer */ 1232 SHR_BITCOPY_RANGE( 1233 (SHR_BITDCL *)history, boff, (SHR_BITDCL *)fldbuf, soff, sbits); 1234 1235 /* Advance offsets and remaining bits */ 1236 poff += sbits; 1237 off += sbits; 1238 pbits -= sbits; 1239 boff += sbits; 1240 left -= sbits; 1241 } 1242 1243 /* Update position for next slice */ 1244 pos += sz; 1245 } 1246 1247 *actual = max_size; 1248 return BCM_E_NONE; 1249 } 1250 1251 /* SR flow mgmt - write seqnum history pool for a flow */ 1252 STATIC int 1253 bcmi_gh2_tsn_sr_flows_seqnum_hist_write( 1254 int unit, 1255 int idx, 1256 int winsize, 1257 bcmi_tsn_sr_seqnum_slice_t slice, 1258 int offset, 1259 int size, 1260 uint8 *history) 1261 { 1262 tsn_sr_seqnum_slice_t *sn, *slices[TSN_SRFLOWS_RX_SN_HIST_POOLS]; 1263 int left; /* bits left to write */ 1264 int off; /* current offset to write for this flow */ 1265 int pos; /* starting position within the flow for a slice */ 1266 int sz; /* size of the slice */ 1267 int poff; /* current offset within a pool */ 1268 int pbits; /* bits to write within a pool */ 1269 int sidx; /* sub pool (per memory access) index */ 1270 int soff; /* current offset within a sub pool */ 1271 int sbits; /* bits to write within a sub pool */ 1272 int boff; /* buffer offset in bits */ 1273 uint32 bsel; /* seqnum sub pool block select */ 1274 soc_mem_t mem; 1275 sr_sn_history_0_entry_t hist_entry; 1276 uint32 fldbuf[TSN_SRFLOWS_RX_SN_HIST_MEM_SIZE / sizeof(uint32)]; 1277 int rv; 1278 int i, j, k; 1279 1280 /* parameter check */ 1281 TSN_BKINFO_IS_INIT(unit); 1282 if (!soc_feature(unit, soc_feature_tsn_sr)) { 1283 return (BCM_E_UNAVAIL); 1284 } 1285 if (NULL == history || NULL == slice || 1286 idx < 0 || idx >= SRFLOWS_BKINFO(unit).max_flows_rx || 1287 (winsize < TSN_SRFLOWS_RX_WINDOW_SIZE_MIN && winsize != 1) || 1288 winsize > TSN_SRFLOWS_RX_WINDOW_SIZE_MAX) { 1289 return BCM_E_PARAM; 1290 } 1291 1292 /* Put slice in the order of pool index and validate */ 1293 for (i = 0; i < TSN_SRFLOWS_RX_SN_HIST_POOLS; i++) { 1294 slices[i] = NULL; 1295 } 1296 pos = 0; 1297 for (sn = (tsn_sr_seqnum_slice_t *)slice; sn != NULL; sn = sn->next) { 1298 if (sn->index < 0 || sn->index >= TSN_SRFLOWS_RX_SN_HIST_POOLS) { 1299 return BCM_E_PARAM; 1300 } 1301 if (slices[sn->index] != NULL) { 1302 return BCM_E_PARAM; 1303 } 1304 slices[sn->index] = sn; 1305 if (sn->power < TSN_SRFLOWS_RX_SNPOOL_POWER_MIN || 1306 sn->power > TSN_SRFLOWS_RX_SNPOOL_POWER_MAX) { 1307 return BCM_E_PARAM; 1308 } 1309 pos += tsn_math_powers[sn->power]; 1310 } 1311 if (pos != winsize) { 1312 if (pos != TSN_SRFLOWS_RX_SNPOOL_SIZE_MIN || winsize != 1) { 1313 /* The only case that pos != winsize is that winsize = 1 */ 1314 return BCM_E_PARAM; 1315 } 1316 } 1317 1318 /* Writing across winsize is not allowed */ 1319 if (size > (winsize - offset)) { 1320 return BCM_E_PARAM; 1321 } 1322 1323 /* Try to write it pool by pool */ 1324 off = offset; /* Offset of this flow */ 1325 left = size; /* Remaining bits to write */ 1326 pos = 0; /* Slice starting position of this flow */ 1327 boff = 0; /* Buffer offset */ 1328 for (i = 0; i < TSN_SRFLOWS_RX_SN_HIST_POOLS; i++) { 1329 if (slices[i] == NULL) { 1330 continue; 1331 } 1332 sn = slices[i]; 1333 sz = tsn_math_powers[sn->power]; /* Size of this slice */ 1334 1335 /* Check if our target is within this slice */ 1336 if (off < pos || off >= pos + sz) { 1337 pos += sz; 1338 continue; 1339 } 1340 1341 /* Calculate starting offset within this pool */ 1342 poff = sn->offset + (off - pos); 1343 1344 /* Calculate bits to write within this pool */ 1345 pbits = sz - (off - pos); 1346 pbits = (pbits > left) ? left : pbits; 1347 1348 /* Loop through sub pools */ 1349 for (j = 0; pbits > 0 && j < TSN_SRFLOWS_RX_SN_HIST_SUB_POOLS; j++) { 1350 /* Check if we need to write this sub pool */ 1351 if (poff < j * TSN_SRFLOWS_RX_SN_HIST_MEM_SIZE || 1352 poff >= (j + 1) * TSN_SRFLOWS_RX_SN_HIST_MEM_SIZE) { 1353 continue; 1354 } 1355 1356 /* Calculate actual HW sub pool index */ 1357 sidx = (i << TSN_SRFLOWS_RX_SN_HIST_SUB_INDEX) | 1358 (poff >> TSN_SRFLOWS_RX_SN_HIST_MEM_POWER); 1359 1360 /* read the entry and the field from the sub pool */ 1361 assert(sidx < sizeof(tsn_flow_sr_hist_pools) / sizeof(soc_mem_t)); 1362 mem = tsn_flow_sr_hist_pools[sidx]; 1363 sal_memset(&hist_entry, 0, sizeof(hist_entry)); 1364 MEM_LOCK(unit, mem); 1365 rv = soc_mem_read(unit, mem, MEM_BLOCK_ANY, sn->entry, &hist_entry); 1366 if (SOC_FAILURE(rv)) { 1367 LOG_ERROR(BSL_LS_BCM_TSN, 1368 (BSL_META_U(unit, "Failed to read mem[%s]"), 1369 SOC_MEM_NAME(unit, mem))); 1370 MEM_UNLOCK(unit, mem); 1371 return rv; 1372 } 1373 soc_mem_field_get( 1374 unit, mem, (uint32 *)&hist_entry, SN_WINDOWf, fldbuf); 1375 1376 /* Calculate starting offset within this sub pool */ 1377 soff = poff & (TSN_SRFLOWS_RX_SN_HIST_MEM_SIZE - 1); 1378 1379 /* Calculate bits to write within this sub pool */ 1380 sbits = TSN_SRFLOWS_RX_SN_HIST_MEM_SIZE - soff; 1381 sbits = (sbits > pbits) ? pbits : sbits; 1382 1383 /* Fill block selections */ 1384 bsel = 0; 1385 for (k = 0; 1386 k < TSN_SRFLOWS_RX_SN_HIST_MEM_SIZE / 1387 TSN_SRFLOWS_RX_SN_HIST_BLOCK_SIZE; 1388 k++) { 1389 if (soff < (k + 1) * TSN_SRFLOWS_RX_SN_HIST_BLOCK_SIZE && 1390 soff + sbits > k * TSN_SRFLOWS_RX_SN_HIST_BLOCK_SIZE) { 1391 bsel |= 1 << k; 1392 } 1393 } 1394 soc_mem_field32_set(unit, mem, &hist_entry, BLOCK_SELECTf, bsel); 1395 1396 /* Copy bits from buffer to field */ 1397 SHR_BITCOPY_RANGE( 1398 (SHR_BITDCL *)fldbuf, soff, (SHR_BITDCL *)history, boff, sbits); 1399 soc_mem_field_set( 1400 unit, mem, (uint32 *)&hist_entry, SN_WINDOWf, fldbuf); 1401 1402 /* Write to HW */ 1403 rv = soc_mem_write( 1404 unit, mem, MEM_BLOCK_ALL, sn->entry, &hist_entry); 1405 if (SOC_FAILURE(rv)) { 1406 LOG_ERROR(BSL_LS_BCM_TSN, 1407 (BSL_META_U(unit, "Failed to write mem[%s]"), 1408 SOC_MEM_NAME(unit, mem))); 1409 MEM_UNLOCK(unit, mem); 1410 return rv; 1411 } 1412 MEM_UNLOCK(unit, mem); 1413 1414 /* Advance offsets and remaining bits */ 1415 poff += sbits; 1416 off += sbits; 1417 pbits -= sbits; 1418 boff += sbits; 1419 left -= sbits; 1420 } 1421 1422 /* Update position for next slice */ 1423 pos += sz; 1424 } 1425 1426 return BCM_E_NONE; 1427 } 1428 1429 /* SR flow mgmt - reset seqnum history pool for a flow */ 1430 STATIC int 1431 bcmi_gh2_tsn_sr_flows_seqnum_hist_reset( 1432 int unit, 1433 int idx, 1434 int winsize, 1435 bcmi_tsn_sr_seqnum_slice_t slice, 1436 uint32 reset_mode) 1437 { 1438 uint8 history[BITS2BYTES(TSN_SRFLOWS_RX_WINDOW_SIZE_MAX)]; 1439 1440 /* parameter check */ 1441 TSN_BKINFO_IS_INIT(unit); 1442 if (!soc_feature(unit, soc_feature_tsn_sr)) { 1443 return (BCM_E_UNAVAIL); 1444 } 1445 if (NULL == slice || 1446 idx < 0 || idx >= SRFLOWS_BKINFO(unit).max_flows_rx || 1447 (winsize < TSN_SRFLOWS_RX_WINDOW_SIZE_MIN && winsize != 1) || 1448 winsize > TSN_SRFLOWS_RX_WINDOW_SIZE_MAX) { 1449 return BCM_E_PARAM; 1450 } 1451 1452 /* Prepare seqnum values */ 1453 if (reset_mode == BCM_TSN_CONTROL_SR_SEQNUM_WINDOW_RESET_MODE_HW1 || 1454 reset_mode == BCM_TSN_CONTROL_SR_SEQNUM_WINDOW_RESET_MODE_SW) { 1455 /* All zeroes */ 1456 sal_memset(history, 0, BITS2BYTES(winsize)); 1457 } else if (reset_mode == BCM_TSN_CONTROL_SR_SEQNUM_WINDOW_RESET_MODE_HW2) { 1458 /* All 1's except the last bit */ 1459 if (winsize == 1) { 1460 /* Special case: 1 bit (it's the first bit in this byte) */ 1461 history[0] = 0; 1462 } else { 1463 sal_memset(history, 0xff, BITS2BYTES(winsize)); 1464 history[BITS2BYTES(winsize) - 1] &= ~0x80; 1465 } 1466 } else { 1467 /* Reset mode not supported */ 1468 return BCM_E_UNAVAIL; 1469 } 1470 1471 /* Call write routine to write the values */ 1472 return bcmi_gh2_tsn_sr_flows_seqnum_hist_write( 1473 unit, idx, winsize, slice, 0, winsize, history); 1474 } 1475 1476 /* SR flow mgmt - clean up seqnum history slice pools */ 1477 STATIC int 1478 bcmi_gh2_tsn_sr_flows_seqnum_slices_cleanup(int unit) 1479 { 1480 int i, j; 1481 1482 /* Free resources */ 1483 TSN_BKINFO_IS_INIT(unit); 1484 if (SRFLOWS_BKINFO(unit).sn_entries_allocated != NULL) { 1485 sal_free(SRFLOWS_BKINFO(unit).sn_entries_allocated); 1486 SRFLOWS_BKINFO(unit).sn_entries_allocated = NULL; 1487 } 1488 if (SRFLOWS_BKINFO(unit).snpool_mutex != NULL) { 1489 sal_mutex_destroy(SRFLOWS_BKINFO(unit).snpool_mutex); 1490 SRFLOWS_BKINFO(unit).snpool_mutex = NULL; 1491 } 1492 1493 /* Clear values */ 1494 SRFLOWS_BKINFO(unit).sn_entries_avail = NULL; 1495 for (i = 0; i < TSN_SRFLOWS_RX_SN_HIST_POOLS; i++) { 1496 for (j = 0; j < TSN_SRFLOWS_RX_SNPOOL_SIZE_COUNT; j++) { 1497 SR_SNPOOL(i, j) = NULL; 1498 } 1499 } 1500 1501 return BCM_E_NONE; 1502 } 1503 1504 /* SR flow mgmt - intiailize seqnum history slice pools */ 1505 STATIC int 1506 bcmi_gh2_tsn_sr_flows_seqnum_slices_init(int unit) 1507 { 1508 tsn_sr_seqnum_slice_t *slice; 1509 uint32 entries; 1510 uint32 i, j; 1511 1512 TSN_BKINFO_IS_INIT(unit); 1513 1514 /* Calculate max entries to be pre-allcoated */ 1515 entries = (uint32)soc_mem_index_count(unit, SR_SN_HISTORY_0m); 1516 j = entries * /* entries per pool */ 1517 TSN_SRFLOWS_RX_SN_HIST_POOL_SIZE * /* size per entry */ 1518 TSN_SRFLOWS_RX_SN_HIST_POOLS /* pools */ 1519 / TSN_SRFLOWS_RX_SNPOOL_SIZE_MIN; /* min slice size */ 1520 1521 /* Pre-allocate slice entries for efficiency */ 1522 SRFLOWS_BKINFO(unit).sn_entries_allocated = (tsn_sr_seqnum_slice_t *) 1523 sal_alloc(sizeof(tsn_sr_seqnum_slice_t) * j, "tsn sr sn slices"); 1524 if (SRFLOWS_BKINFO(unit).sn_entries_allocated == NULL) { 1525 LOG_ERROR(BSL_LS_BCM_TSN, 1526 (BSL_META("TSN SR: failed to allocate SN pool slices\n"))); 1527 return BCM_E_MEMORY; 1528 } 1529 1530 /* Initialize the free slice entries list by hooking them together */ 1531 slice = SRFLOWS_BKINFO(unit).sn_entries_allocated; 1532 for (i = 0; i < j - 1; i++) { 1533 slice[i].next = &slice[i + 1]; 1534 } 1535 slice[j - 1].next = NULL; 1536 SRFLOWS_BKINFO(unit).sn_entries_avail = &slice[0]; 1537 1538 /* Initialize slices linked list for all sizes */ 1539 for (i = 0; i < TSN_SRFLOWS_RX_SN_HIST_POOLS; i++) { 1540 for (j = 0; j < TSN_SRFLOWS_RX_SNPOOL_SIZE_COUNT; j++) { 1541 SR_SNPOOL(i, j) = NULL; 1542 } 1543 } 1544 1545 /* Create mutex for protecting seqnum slices */ 1546 SRFLOWS_BKINFO(unit).snpool_mutex = sal_mutex_create("tsn sr sn pool"); 1547 if (NULL == SRFLOWS_BKINFO(unit).snpool_mutex) { 1548 LOG_ERROR(BSL_LS_BCM_TSN, 1549 (BSL_META("TSN SR: failed to create SN pool mutex\n"))); 1550 (void)bcmi_gh2_tsn_sr_flows_seqnum_slices_cleanup(unit); 1551 return BCM_E_MEMORY; 1552 } 1553 1554 /* Prepare the entries with max size for seqnum allocation */ 1555 for (i = 0; i < TSN_SRFLOWS_RX_SN_HIST_POOLS; i++) { 1556 /* Add max-size slices */ 1557 for (j = 0; j < entries; j++) { 1558 1559 /* Get one empty entry */ 1560 slice = SRFLOWS_BKINFO(unit).sn_entries_avail; 1561 SRFLOWS_BKINFO(unit).sn_entries_avail = slice->next; 1562 1563 /* Fill with entry info and max size */ 1564 slice->index = i; 1565 slice->entry = entries - j - 1; 1566 slice->offset = 0; 1567 slice->power = TSN_SRFLOWS_RX_SNPOOL_POWER_MAX; 1568 1569 /* Hook to it */ 1570 slice->next = SR_SNPOOL(i, TSN_SRFLOWS_RX_SNPOOL_IDX_MAX); 1571 SR_SNPOOL(i, TSN_SRFLOWS_RX_SNPOOL_IDX_MAX) = slice; 1572 } 1573 } 1574 1575 return BCM_E_NONE; 1576 } 1577 1578 /* SR flow mgmt - get number of RX/TX flows */ 1579 STATIC int 1580 bcmi_gh2_tsn_sr_flows_get_num_flows(int unit, int *rx_flows, int *tx_flows) 1581 { 1582 /* parameter check */ 1583 TSN_BKINFO_IS_INIT(unit); 1584 if (!soc_feature(unit, soc_feature_tsn_sr)) { 1585 return (BCM_E_UNAVAIL); 1586 } 1587 if (NULL == rx_flows || NULL == tx_flows) { 1588 return BCM_E_PARAM; 1589 } 1590 1591 /* Get the flows based on number of entries in HW memory (if not yet) */ 1592 if (SRFLOWS_BKINFO(unit).max_flows_rx == 0) { 1593 1594 /* The actual valid flow count - 1 since HW flow 0 is invalid */ 1595 SRFLOWS_BKINFO(unit).max_flows_rx = 1596 soc_mem_index_count(unit, SR_RXm) - 1; 1597 SRFLOWS_BKINFO(unit).max_flows_tx = 1598 soc_mem_index_count(unit, SR_TXm) - 1; 1599 } 1600 1601 /* Return the cached values */ 1602 *rx_flows = SRFLOWS_BKINFO(unit).max_flows_rx; 1603 *tx_flows = SRFLOWS_BKINFO(unit).max_flows_tx; 1604 1605 return BCM_E_NONE; 1606 } 1607 1608 /* SR flow mgmt - convert flow index to HW flow ID */ 1609 STATIC int 1610 bcmi_gh2_tsn_sr_flows_get_hw_flow_id( 1611 int unit, 1612 int is_tx, 1613 int fidx, 1614 uint32 *hw_id) 1615 { 1616 /* parameter check */ 1617 TSN_BKINFO_IS_INIT(unit); 1618 if (!soc_feature(unit, soc_feature_tsn_sr)) { 1619 return (BCM_E_UNAVAIL); 1620 } 1621 if (NULL == hw_id || fidx < 0) { 1622 return BCM_E_PARAM; 1623 } 1624 1625 /* Check if it's valid */ 1626 if (is_tx) { 1627 if (fidx >= SRFLOWS_BKINFO(unit).max_flows_tx) { 1628 return BCM_E_PARAM; 1629 } 1630 } else { 1631 if (fidx >= SRFLOWS_BKINFO(unit).max_flows_rx) { 1632 return BCM_E_PARAM; 1633 } 1634 } 1635 1636 /* Convert it */ 1637 *hw_id = (uint32)TSN_SRFLOWS_IDX_TO_HW_ID(is_tx, fidx); 1638 return BCM_E_NONE; 1639 } 1640 1641 /* SR flow mgmt - convert flow index to HW flow ID */ 1642 STATIC int 1643 bcmi_gh2_tsn_sr_flows_get_sw_flow_idx( 1644 int unit, 1645 uint32 hw_id, 1646 int *is_tx, 1647 int *fidx) 1648 { 1649 int tx; 1650 int idx; 1651 1652 /* parameter check */ 1653 if (!soc_feature(unit, soc_feature_tsn_sr)) { 1654 return (BCM_E_UNAVAIL); 1655 } 1656 if (NULL == is_tx || NULL == fidx) { 1657 return BCM_E_PARAM; 1658 } 1659 1660 /* Convert it */ 1661 tx = TSN_SRFLOWS_HW_ID_IS_TX((int)hw_id); 1662 idx = TSN_SRFLOWS_HW_ID_TO_IDX((int)hw_id); 1663 1664 /* Check if it's valid */ 1665 if (TSN_BKINFO(unit) != NULL) { 1666 TSN_BKINFO_IS_INIT(unit); 1667 if (tx) { 1668 if (idx < 0 || idx >= SRFLOWS_BKINFO(unit).max_flows_tx) { 1669 return BCM_E_PARAM; 1670 } 1671 } else { 1672 if (idx < 0 || idx >= SRFLOWS_BKINFO(unit).max_flows_rx) { 1673 return BCM_E_PARAM; 1674 } 1675 } 1676 } 1677 1678 *is_tx = tx; 1679 *fidx = idx; 1680 return BCM_E_NONE; 1681 } 1682 1683 /* SR flow mgmt - check flow config */ 1684 STATIC int 1685 bcmi_gh2_tsn_sr_flows_check_rx_flow_config( 1686 int unit, 1687 bcm_tsn_sr_rx_flow_config_t *cfg) 1688 { 1689 int index; 1690 bcm_tsn_mtu_profile_type_t type; 1691 1692 /* parameter check */ 1693 TSN_BKINFO_IS_INIT(unit); 1694 if (!soc_feature(unit, soc_feature_tsn_sr)) { 1695 return (BCM_E_UNAVAIL); 1696 } 1697 if (NULL == cfg) { 1698 return BCM_E_PARAM; 1699 } 1700 1701 /* Check min/max window sizes (special case: history size can be 1) */ 1702 if ((cfg->seqnum_history_win_size != 1 && 1703 cfg->seqnum_history_win_size < TSN_SRFLOWS_RX_WINDOW_SIZE_MIN) || 1704 cfg->seqnum_history_win_size > TSN_SRFLOWS_RX_WINDOW_SIZE_MAX || 1705 cfg->seqnum_accept_win_size < TSN_SRFLOWS_RX_ACCEPT_SIZE_MIN || 1706 cfg->seqnum_accept_win_size > TSN_SRFLOWS_RX_ACCEPT_SIZE_MAX) { 1707 return BCM_E_PARAM; 1708 } 1709 1710 /* Check if they're power of 2 */ 1711 if (!TSN_IS_POWER_OF_2(cfg->seqnum_accept_win_size) || 1712 !TSN_IS_POWER_OF_2(cfg->seqnum_history_win_size)) { 1713 return BCM_E_PARAM; 1714 } 1715 1716 /* History window size should be smaller than acceptance window size */ 1717 if (cfg->seqnum_history_win_size >= cfg->seqnum_accept_win_size) { 1718 return BCM_E_PARAM; 1719 } 1720 1721 /* Check age out time (for GH2, it must be power of 2) */ 1722 if (!TSN_IS_POWER_OF_2(cfg->age_timeout) || 1723 cfg->age_timeout > TSN_SRFLOWS_RX_AGE_TIME_MAX) { 1724 return BCM_E_PARAM; 1725 } 1726 1727 /* Check flags */ 1728 if (cfg->flags & 1729 ~(BCM_TSN_SR_RX_FLOW_CONFIG_ACCEPT_DUPLICATES | 1730 BCM_TSN_SR_RX_FLOW_CONFIG_ACCEPT_PKT_IN_DROP_WINDOW | 1731 BCM_TSN_SR_RX_FLOW_CONFIG_DROP_OUT_OF_ORDER | 1732 BCM_TSN_SR_RX_FLOW_CONFIG_DO_NOT_CUT_THROUGH)) { 1733 /* Found unsupported flags */ 1734 return BCM_E_UNAVAIL; 1735 } 1736 1737 /* Check MTU profile id */ 1738 if (soc_feature(unit, soc_feature_tsn_mtu_stu)) { 1739 /* Using MTU decode function to do profile id validation */ 1740 BCM_IF_ERROR_RETURN(bcmi_gh2_tsn_mtu_profile_decode( 1741 unit, cfg->ingress_mtu_profile, &type, &index)); 1742 if (type == bcmTsnMtuProfileTypeEgress) { 1743 return BCM_E_PARAM; 1744 } 1745 } 1746 1747 return BCM_E_NONE; 1748 } 1749 1750 /* SR flow mgmt - check flow config */ 1751 STATIC int 1752 bcmi_gh2_tsn_sr_flows_check_tx_flow_config( 1753 int unit, 1754 bcm_tsn_sr_tx_flow_config_t *cfg) 1755 { 1756 int index; 1757 bcm_tsn_mtu_profile_type_t type; 1758 1759 /* parameter check */ 1760 TSN_BKINFO_IS_INIT(unit); 1761 if (!soc_feature(unit, soc_feature_tsn_sr)) { 1762 return (BCM_E_UNAVAIL); 1763 } 1764 if (NULL == cfg) { 1765 return BCM_E_PARAM; 1766 } 1767 1768 /* check sequence number */ 1769 if (cfg->seq_num > TSN_SRFLOWS_SEQNUM_VALUE_MAX) { 1770 return BCM_E_PARAM; 1771 } 1772 1773 /* Check MTU profile id */ 1774 if (soc_feature(unit, soc_feature_tsn_mtu_stu)) { 1775 /* Using MTU decode function to do profile id validation */ 1776 BCM_IF_ERROR_RETURN(bcmi_gh2_tsn_mtu_profile_decode( 1777 unit, cfg->ingress_mtu_profile, &type, &index)); 1778 if (type == bcmTsnMtuProfileTypeEgress) { 1779 return BCM_E_PARAM; 1780 } 1781 1782 } 1783 1784 return BCM_E_NONE; 1785 } 1786 1787 /* SR flow mgmt - clear flow config - mtu */ 1788 STATIC int 1789 bcmi_gh2_tsn_sr_flows_clear_rx_flow_mtu(int unit, int idx) 1790 { 1791 soc_mem_t mem; 1792 ing_mtu_check_2_entry_t mtu_ent; 1793 int rv; 1794 int is_tx = 0; 1795 uint32 hw_id; 1796 1797 TSN_BKINFO_IS_INIT(unit); 1798 if (!soc_feature(unit, soc_feature_tsn_mtu_stu)) { 1799 return BCM_E_UNAVAIL; 1800 } 1801 1802 hw_id = (uint32)TSN_SRFLOWS_IDX_TO_HW_ID(is_tx, idx); 1803 mem = ING_MTU_CHECK_2m; 1804 sal_memset(&mtu_ent, 0, sizeof(mtu_ent)); 1805 MEM_LOCK(unit, mem); 1806 rv = soc_mem_read(unit, mem, MEM_BLOCK_ANY, hw_id, &mtu_ent); 1807 if (SOC_FAILURE(rv)) { 1808 LOG_ERROR(BSL_LS_BCM_TSN, 1809 (BSL_META_U(unit, "Failed to read mem[%s]"), 1810 SOC_MEM_NAME(unit, mem))); 1811 MEM_UNLOCK(unit, mem); 1812 return rv; 1813 } 1814 soc_mem_field32_set(unit, mem, &mtu_ent, MTU_PROFILE_INDEXf, 0); 1815 1816 rv = soc_mem_write(unit, mem, MEM_BLOCK_ALL, hw_id, &mtu_ent); 1817 if (SOC_FAILURE(rv)) { 1818 LOG_ERROR(BSL_LS_BCM_TSN, 1819 (BSL_META_U(unit, "Failed to write mem[%s]"), 1820 SOC_MEM_NAME(unit, mem))); 1821 MEM_UNLOCK(unit, mem); 1822 return rv; 1823 } 1824 MEM_UNLOCK(unit, mem); 1825 return BCM_E_NONE; 1826 } 1827 1828 /* SR flow mgmt - clear flow config */ 1829 STATIC int 1830 bcmi_gh2_tsn_sr_flows_clear_rx_flow(int unit, int idx) 1831 { 1832 soc_mem_t mem; 1833 sr_rx_entry_t entry; 1834 int rv; 1835 1836 /* parameter check */ 1837 TSN_BKINFO_IS_INIT(unit); 1838 if (!soc_feature(unit, soc_feature_tsn_sr)) { 1839 return (BCM_E_UNAVAIL); 1840 } 1841 if (idx < 0 || idx >= SRFLOWS_BKINFO(unit).max_flows_rx) { 1842 return BCM_E_PARAM; 1843 } 1844 1845 /* Clear the entry with HW index idx+1 since entry 0 is not visible */ 1846 mem = SR_RXm; 1847 sal_memset(&entry, 0, sizeof(entry)); 1848 rv = soc_mem_write(unit, mem, MEM_BLOCK_ALL, idx + 1, &entry); 1849 if (SOC_FAILURE(rv)) { 1850 LOG_ERROR(BSL_LS_BCM_TSN, 1851 (BSL_META_U(unit, "Failed to write mem[%s]"), 1852 SOC_MEM_NAME(unit, mem))); 1853 return rv; 1854 } 1855 1856 /* Clear MTU profile id HW */ 1857 if (soc_feature(unit, soc_feature_tsn_mtu_stu)) { 1858 rv = bcmi_gh2_tsn_sr_flows_clear_rx_flow_mtu(unit, idx); 1859 if (SOC_FAILURE(rv)) { 1860 LOG_ERROR(BSL_LS_BCM_TSN, 1861 (BSL_META_U(unit, "Failed to clear mem[%s]"), 1862 SOC_MEM_NAME(unit, mem))); 1863 return rv; 1864 } 1865 } 1866 1867 return BCM_E_NONE; 1868 } 1869 1870 /* SR flow mgmt - clear flow config - mtu */ 1871 STATIC int 1872 bcmi_gh2_tsn_sr_flows_clear_tx_flow_mtu(int unit, int idx) 1873 { 1874 soc_mem_t mem; 1875 ing_mtu_check_2_entry_t mtu_ent; 1876 int rv; 1877 int is_tx = 1; 1878 uint32 hw_id; 1879 1880 TSN_BKINFO_IS_INIT(unit); 1881 if (!soc_feature(unit, soc_feature_tsn_mtu_stu)) { 1882 return BCM_E_UNAVAIL; 1883 } 1884 1885 hw_id = (uint32)TSN_SRFLOWS_IDX_TO_HW_ID(is_tx, idx); 1886 mem = ING_MTU_CHECK_2m; 1887 sal_memset(&mtu_ent, 0, sizeof(mtu_ent)); 1888 MEM_LOCK(unit, mem); 1889 rv = soc_mem_read(unit, mem, MEM_BLOCK_ANY, hw_id, &mtu_ent); 1890 if (SOC_FAILURE(rv)) { 1891 LOG_ERROR(BSL_LS_BCM_TSN, 1892 (BSL_META_U(unit, "Failed to read mem[%s]"), 1893 SOC_MEM_NAME(unit, mem))); 1894 MEM_UNLOCK(unit, mem); 1895 return rv; 1896 } 1897 soc_mem_field32_set(unit, mem, &mtu_ent, MTU_PROFILE_INDEXf, 0); 1898 1899 rv = soc_mem_write(unit, mem, MEM_BLOCK_ALL, hw_id, &mtu_ent); 1900 if (SOC_FAILURE(rv)) { 1901 LOG_ERROR(BSL_LS_BCM_TSN, 1902 (BSL_META_U(unit, "Failed to write mem[%s]"), 1903 SOC_MEM_NAME(unit, mem))); 1904 MEM_UNLOCK(unit, mem); 1905 return rv; 1906 } 1907 1908 MEM_UNLOCK(unit, mem); 1909 return BCM_E_NONE; 1910 } 1911 1912 /* SR flow mgmt - clear flow config */ 1913 STATIC int 1914 bcmi_gh2_tsn_sr_flows_clear_tx_flow(int unit, int idx) 1915 { 1916 soc_mem_t mem; 1917 sr_tx_entry_t entry; 1918 int rv; 1919 1920 /* parameter check */ 1921 TSN_BKINFO_IS_INIT(unit); 1922 if (!soc_feature(unit, soc_feature_tsn_sr)) { 1923 return (BCM_E_UNAVAIL); 1924 } 1925 if (idx < 0 || idx >= SRFLOWS_BKINFO(unit).max_flows_tx) { 1926 return BCM_E_PARAM; 1927 } 1928 1929 /* Write to HW with HW index idx+1 since entry 0 is not visible to SW */ 1930 mem = SR_TXm; 1931 sal_memset(&entry, 0, sizeof(entry)); 1932 MEM_LOCK(unit, mem); 1933 rv = soc_mem_read(unit, mem, MEM_BLOCK_ANY, idx + 1, &entry); 1934 if (SOC_FAILURE(rv)) { 1935 LOG_ERROR(BSL_LS_BCM_TSN, 1936 (BSL_META_U(unit, "Failed to read mem[%s]"), 1937 SOC_MEM_NAME(unit, mem))); 1938 MEM_UNLOCK(unit, mem); 1939 return rv; 1940 } 1941 soc_mem_field32_set( 1942 unit, mem, &entry, NEXT_SNf, TSN_SRFLOWS_DEFAULT_NEXT_SN); 1943 rv = soc_mem_write(unit, mem, MEM_BLOCK_ALL, idx + 1, &entry); 1944 if (SOC_FAILURE(rv)) { 1945 LOG_ERROR(BSL_LS_BCM_TSN, 1946 (BSL_META_U(unit, "Failed to write mem[%s]"), 1947 SOC_MEM_NAME(unit, mem))); 1948 MEM_UNLOCK(unit, mem); 1949 return rv; 1950 } 1951 1952 /* Clear MTU profile id HW */ 1953 if (soc_feature(unit, soc_feature_tsn_mtu_stu)) { 1954 rv = bcmi_gh2_tsn_sr_flows_clear_tx_flow_mtu(unit, idx); 1955 if (SOC_FAILURE(rv)) { 1956 LOG_ERROR(BSL_LS_BCM_TSN, 1957 (BSL_META_U(unit, "Failed to clear mem[%s]"), 1958 SOC_MEM_NAME(unit, mem))); 1959 MEM_UNLOCK(unit, mem); 1960 return rv; 1961 } 1962 } 1963 MEM_UNLOCK(unit, mem); 1964 1965 return BCM_E_NONE; 1966 } 1967 1968 /* SR flow mgmt - reset RX flow */ 1969 STATIC int 1970 bcmi_gh2_tsn_sr_flows_reset_rx_flow(int unit, int idx, uint32 flags) 1971 { 1972 soc_mem_t mem; 1973 sr_rx_entry_t entry; 1974 uint32 v; 1975 int rv; 1976 1977 /* parameter check */ 1978 TSN_BKINFO_IS_INIT(unit); 1979 if (!soc_feature(unit, soc_feature_tsn_sr)) { 1980 return (BCM_E_UNAVAIL); 1981 } 1982 if (idx < 0 || idx >= SRFLOWS_BKINFO(unit).max_flows_rx) { 1983 return BCM_E_PARAM; 1984 } 1985 1986 /* Write to HW with HW index idx+1 since entry 0 is not visible to SW */ 1987 mem = SR_RXm; 1988 sal_memset(&entry, 0, sizeof(entry)); 1989 MEM_LOCK(unit, mem); 1990 rv = soc_mem_read(unit, mem, MEM_BLOCK_ANY, idx + 1, &entry); 1991 if (SOC_FAILURE(rv)) { 1992 LOG_ERROR(BSL_LS_BCM_TSN, 1993 (BSL_META_U(unit, "Failed to read mem[%s]"), 1994 SOC_MEM_NAME(unit, mem))); 1995 MEM_UNLOCK(unit, mem); 1996 return rv; 1997 } 1998 1999 /* seqnum age count down and wrong LAN clear count down */ 2000 v = soc_mem_field32_get(unit, mem, &entry, SN_AGE_OUT_ENABLEf); 2001 if (v) { 2002 /* Calculate the countdown if aging enabled, otherwise fill with 0 */ 2003 v = 1 << soc_mem_field32_get(unit, mem, &entry, AGE_OUT_MULTIPLIERf); 2004 } 2005 if (flags & BCM_TSN_SR_RX_FLOW_RESET_SEQNUM_AGE_COUNTDOWN) { 2006 soc_mem_field32_set( 2007 unit, mem, &entry, SN_AGE_OUT_COUNT_DOWNf, v); 2008 } 2009 if (flags & BCM_TSN_SR_RX_FLOW_RESET_WRONGLAN_A_AGE_COUNTDOWN) { 2010 /* Reset the value only if the indicator bit is set */ 2011 if (soc_mem_field32_get(unit, mem, &entry, WRONG_LAN_Af)) { 2012 soc_mem_field32_set( 2013 unit, mem, &entry, WRONG_LAN_A_AGE_OUT_COUNT_DOWNf, v); 2014 } 2015 } 2016 if (flags & BCM_TSN_SR_RX_FLOW_RESET_WRONGLAN_B_AGE_COUNTDOWN) { 2017 /* Reset the value only if the indicator bit is set */ 2018 if (soc_mem_field32_get(unit, mem, &entry, WRONG_LAN_Bf)) { 2019 soc_mem_field32_set( 2020 unit, mem, &entry, WRONG_LAN_B_AGE_OUT_COUNT_DOWNf, v); 2021 } 2022 } 2023 2024 /* seqnum reset state */ 2025 if (flags & BCM_TSN_SR_RX_FLOW_RESET_SEQNUM_WIN_STATE) { 2026 soc_mem_field32_set(unit, mem, &entry, SN_RESET_STATEf, 1); 2027 } 2028 2029 /* Do final writing */ 2030 rv = soc_mem_write(unit, mem, MEM_BLOCK_ALL, idx + 1, &entry); 2031 if (SOC_FAILURE(rv)) { 2032 LOG_ERROR(BSL_LS_BCM_TSN, 2033 (BSL_META_U(unit, "Failed to write mem[%s]"), 2034 SOC_MEM_NAME(unit, mem))); 2035 MEM_UNLOCK(unit, mem); 2036 return rv; 2037 } 2038 MEM_UNLOCK(unit, mem); 2039 2040 return BCM_E_NONE; 2041 } 2042 2043 /* SR flow mgmt - write flow config */ 2044 STATIC int 2045 bcmi_gh2_tsn_sr_flows_write_rx_flow( 2046 int unit, 2047 int idx, 2048 bcmi_tsn_sr_rx_flow_t *config) 2049 { 2050 soc_mem_t mem; 2051 sr_rx_entry_t entry; 2052 cut_through_attribute_entry_t ct_entry; 2053 ing_mtu_check_2_entry_t mtu_ent; 2054 bcm_tsn_sr_rx_flow_config_t *cfg; 2055 tsn_sr_seqnum_slice_t *sn; 2056 int entries; 2057 uint32 v; 2058 int power; 2059 int rv; 2060 int i; 2061 int is_tx = 0; 2062 uint32 hw_id; 2063 int mtu_hw_index; 2064 bcm_tsn_mtu_profile_type_t type; 2065 2066 /* parameter check */ 2067 TSN_BKINFO_IS_INIT(unit); 2068 if (!soc_feature(unit, soc_feature_tsn_sr)) { 2069 return (BCM_E_UNAVAIL); 2070 } 2071 if (NULL == config || idx < 0 || 2072 idx >= SRFLOWS_BKINFO(unit).max_flows_rx) { 2073 return BCM_E_PARAM; 2074 } 2075 2076 /* Double check the configuration is correct */ 2077 cfg = &config->config; 2078 BCM_IF_ERROR_RETURN(bcmi_gh2_tsn_sr_flows_check_rx_flow_config(unit, cfg)); 2079 if (config->sn_slice == NULL) { 2080 return BCM_E_PARAM; 2081 } 2082 2083 /* Validate slice before doing anything */ 2084 i = 0; 2085 entries = soc_mem_index_count(unit, SR_SN_HISTORY_0m); 2086 sn = (tsn_sr_seqnum_slice_t *)config->sn_slice; 2087 for (; sn != NULL; sn = sn->next) { 2088 /* The total number of chained slices < number of pools */ 2089 i++; 2090 if (i > TSN_SRFLOWS_RX_SN_HIST_POOLS) { 2091 return BCM_E_PARAM; 2092 } 2093 2094 /* Validate item values */ 2095 if (sn->index < 0 || sn->index >= TSN_SRFLOWS_RX_SN_HIST_POOLS) { 2096 return BCM_E_PARAM; 2097 } 2098 if (sn->power < TSN_SRFLOWS_RX_SNPOOL_POWER_MIN || 2099 sn->power > TSN_SRFLOWS_RX_SNPOOL_POWER_MAX) { 2100 return BCM_E_PARAM; 2101 } 2102 if (sn->offset < 0 || sn->offset > TSN_SRFLOWS_RX_SNPOOL_SIZE_MAX) { 2103 return BCM_E_PARAM; 2104 } 2105 if (sn->offset % tsn_math_powers[sn->power]) { 2106 /* offset should be multiples of the slice size */ 2107 return BCM_E_PARAM; 2108 } 2109 if (sn->entry < 0 || sn->entry >= entries) { 2110 return BCM_E_PARAM; 2111 } 2112 } 2113 2114 /* 2115 * Per flow disable cut-through 2116 * Write to HW with HW index (idx+flow_type_offset)+1 2117 * since entry 0 is not visible to SW 2118 */ 2119 if (soc_feature(unit, soc_feature_tsn_sr_flow_no_asf_select)) { 2120 mem = CUT_THROUGH_ATTRIBUTEm; 2121 sal_memset(&ct_entry, 0, sizeof(ct_entry)); 2122 v = (cfg->flags & BCM_TSN_SR_RX_FLOW_CONFIG_DO_NOT_CUT_THROUGH) ? 1 : 0; 2123 soc_mem_field32_set(unit, mem, &ct_entry, DO_NOT_CUT_THROUGHf, v); 2124 rv = soc_mem_write(unit, mem, MEM_BLOCK_ALL, 2125 TSN_SRFLOWS_IDX_TO_HW_ID(0, idx), 2126 &ct_entry); 2127 if (SOC_FAILURE(rv)) { 2128 LOG_ERROR(BSL_LS_BCM_TSN, 2129 (BSL_META_U(unit, "Failed to write mem[%s]"), 2130 SOC_MEM_NAME(unit, mem))); 2131 return rv; 2132 } 2133 } else { 2134 if (cfg->flags & BCM_TSN_SR_RX_FLOW_CONFIG_DO_NOT_CUT_THROUGH) { 2135 LOG_VERBOSE(BSL_LS_BCM_TSN, 2136 (BSL_META_U(unit, 2137 "SR RX flow disable cut-through " 2138 "is not configurable\n"))); 2139 return BCM_E_PARAM; 2140 } 2141 } 2142 2143 /* Write to HW with HW index idx+1 since entry 0 is not visible to SW */ 2144 mem = SR_RXm; 2145 sal_memset(&entry, 0, sizeof(entry)); 2146 MEM_LOCK(unit, mem); 2147 rv = soc_mem_read(unit, mem, MEM_BLOCK_ANY, idx + 1, &entry); 2148 if (SOC_FAILURE(rv)) { 2149 LOG_ERROR(BSL_LS_BCM_TSN, 2150 (BSL_META_U(unit, "Failed to read mem[%s]"), 2151 SOC_MEM_NAME(unit, mem))); 2152 MEM_UNLOCK(unit, mem); 2153 return rv; 2154 } 2155 2156 /* Flags */ 2157 v = (cfg->flags & BCM_TSN_SR_RX_FLOW_CONFIG_ACCEPT_DUPLICATES) ? 1 : 0; 2158 soc_mem_field32_set(unit, mem, &entry, ACCEPT_DUPLICATE_PACKETf, v); 2159 v = (cfg->flags & BCM_TSN_SR_RX_FLOW_CONFIG_ACCEPT_PKT_IN_DROP_WINDOW) ? 2160 1 : 0; 2161 soc_mem_field32_set(unit, mem, &entry, ACCEPT_IN_DROP_WINDOWf, v); 2162 v = (cfg->flags & BCM_TSN_SR_RX_FLOW_CONFIG_DROP_OUT_OF_ORDER) ? 1 : 0; 2163 soc_mem_field32_set(unit, mem, &entry, DROP_OUT_OF_ORDERf, v); 2164 2165 /* Acceptance window (already validated as a valid power-of-2 number) */ 2166 TSN_GET_LOG2(cfg->seqnum_accept_win_size, power); 2167 assert(power >= TSN_SRFLOWS_RX_ACCEPT_POWER_MIN && 2168 power <= TSN_SRFLOWS_RX_ACCEPT_POWER_MAX); 2169 v = (uint32)TSN_SRFLOWS_RX_ACCEPT_POWER_MAX - power; 2170 soc_mem_field32_set(unit, mem, &entry, ACCEPTANCE_WINDOW_SIZEf, v); 2171 2172 /* Age out time interval */ 2173 if (cfg->age_timeout == 0) { 2174 /* Disable aging */ 2175 soc_mem_field32_set(unit, mem, &entry, AGE_OUT_MULTIPLIERf, 0); 2176 soc_mem_field32_set(unit, mem, &entry, SN_AGE_OUT_ENABLEf, 0); 2177 } else { 2178 /* The actual multiplier is 2^N */ 2179 TSN_GET_LOG2(cfg->age_timeout, v); 2180 soc_mem_field32_set(unit, mem, &entry, AGE_OUT_MULTIPLIERf, v); 2181 /* Enable aging */ 2182 soc_mem_field32_set(unit, mem, &entry, SN_AGE_OUT_ENABLEf, 1); 2183 } 2184 2185 /* Sequence number history window size (also already validated) */ 2186 if (cfg->seqnum_history_win_size == 1) { 2187 /* Special case: 1-bit */ 2188 v = 0; 2189 } else { 2190 TSN_GET_LOG2(cfg->seqnum_history_win_size, power); 2191 assert(power >= TSN_SRFLOWS_RX_WINDOW_POWER_MIN && 2192 power <= TSN_SRFLOWS_RX_WINDOW_POWER_MAX); 2193 v = (uint32)power - TSN_SRFLOWS_RX_WINDOW_POWER_MIN + 1; 2194 } 2195 soc_mem_field32_set(unit, mem, &entry, SN_WINDOW_SIZEf, v); 2196 2197 /* Clear seqnum pool sizes to 0 (disabled by default) */ 2198 for (i = 0; i < sizeof(tsn_flow_sr_hist_sizes) / sizeof(soc_field_t); i++) { 2199 soc_mem_field32_set(unit, mem, &entry, tsn_flow_sr_hist_sizes[i], 0); 2200 } 2201 2202 /* Write indexes to the seqnum pools */ 2203 sn = (tsn_sr_seqnum_slice_t *)config->sn_slice; 2204 for (; sn != NULL; sn = sn->next) { 2205 soc_mem_field32_set( 2206 unit, mem, &entry, tsn_flow_sr_hist_indexs[sn->index], sn->entry); 2207 soc_mem_field32_set( 2208 unit, mem, &entry, tsn_flow_sr_hist_offsets[sn->index], 2209 sn->offset / TSN_SRFLOWS_RX_SN_HIST_BLOCK_SIZE); 2210 soc_mem_field32_set( 2211 unit, mem, &entry, tsn_flow_sr_hist_sizes[sn->index], 2212 sn->power - TSN_SRFLOWS_RX_SNPOOL_POWER_MIN + 2); 2213 } 2214 2215 /* Do final writing */ 2216 rv = soc_mem_write(unit, mem, MEM_BLOCK_ALL, idx + 1, &entry); 2217 if (SOC_FAILURE(rv)) { 2218 LOG_ERROR(BSL_LS_BCM_TSN, 2219 (BSL_META_U(unit, "Failed to write mem[%s]"), 2220 SOC_MEM_NAME(unit, mem))); 2221 MEM_UNLOCK(unit, mem); 2222 return rv; 2223 } 2224 /* Unlock memory SR_RXm */ 2225 MEM_UNLOCK(unit, mem); 2226 2227 /* MTU profile id HW writing */ 2228 if (soc_feature(unit, soc_feature_tsn_mtu_stu)) { 2229 hw_id = (uint32)TSN_SRFLOWS_IDX_TO_HW_ID(is_tx, idx); 2230 mem = ING_MTU_CHECK_2m; 2231 sal_memset(&mtu_ent, 0, sizeof(mtu_ent)); 2232 MEM_LOCK(unit, mem); 2233 rv = soc_mem_read(unit, mem, MEM_BLOCK_ANY, hw_id, &mtu_ent); 2234 if (SOC_FAILURE(rv)) { 2235 LOG_ERROR(BSL_LS_BCM_TSN, 2236 (BSL_META_U(unit, "Failed to read mem[%s]"), 2237 SOC_MEM_NAME(unit, mem))); 2238 MEM_UNLOCK(unit, mem); 2239 return rv; 2240 } 2241 type = bcmTsnMtuProfileTypeIngress; 2242 rv = bcmi_gh2_tsn_mtu_profile_decode( 2243 unit, cfg->ingress_mtu_profile, 2244 &type, &mtu_hw_index); 2245 if (SOC_FAILURE(rv)) { 2246 LOG_ERROR(BSL_LS_BCM_TSN, 2247 (BSL_META_U(unit, "Failed to decode profile id[%d]"), 2248 cfg->ingress_mtu_profile)); 2249 MEM_UNLOCK(unit, mem); 2250 return rv; 2251 } 2252 soc_mem_field32_set(unit, mem, &mtu_ent, 2253 MTU_PROFILE_INDEXf, mtu_hw_index); 2254 2255 rv = soc_mem_write(unit, mem, MEM_BLOCK_ALL, hw_id, &mtu_ent); 2256 if (SOC_FAILURE(rv)) { 2257 LOG_ERROR(BSL_LS_BCM_TSN, 2258 (BSL_META_U(unit, "Failed to write mem[%s]"), 2259 SOC_MEM_NAME(unit, mem))); 2260 MEM_UNLOCK(unit, mem); 2261 return rv; 2262 } 2263 MEM_UNLOCK(unit, mem); 2264 } 2265 2266 return BCM_E_NONE; 2267 } 2268 2269 /* SR flow mgmt - write flow config */ 2270 STATIC int 2271 bcmi_gh2_tsn_sr_flows_write_tx_flow( 2272 int unit, 2273 int idx, 2274 bcmi_tsn_sr_tx_flow_t *config) 2275 { 2276 soc_mem_t mem; 2277 sr_tx_entry_t entry; 2278 cut_through_attribute_entry_t ct_entry; 2279 ing_mtu_check_2_entry_t mtu_ent; 2280 int rv; 2281 uint32 v = 0; 2282 int is_tx = 1; 2283 uint32 hw_id; 2284 int mtu_hw_index; 2285 bcm_tsn_mtu_profile_type_t type; 2286 bcm_tsn_sr_tx_flow_config_t *cfg; 2287 2288 /* parameter check */ 2289 TSN_BKINFO_IS_INIT(unit); 2290 if (!soc_feature(unit, soc_feature_tsn_sr)) { 2291 return (BCM_E_UNAVAIL); 2292 } 2293 if (NULL == config || idx < 0 || 2294 idx >= SRFLOWS_BKINFO(unit).max_flows_tx) { 2295 return BCM_E_PARAM; 2296 } 2297 2298 /* Double check the configuration is correct */ 2299 cfg = &config->config; 2300 BCM_IF_ERROR_RETURN(bcmi_gh2_tsn_sr_flows_check_tx_flow_config(unit, cfg)); 2301 2302 /* 2303 * Per flow disable cut-through 2304 * Write to HW with HW index (idx+flow_type_offset)+1 2305 * since entry 0 is not visible to SW 2306 */ 2307 if (soc_feature(unit, soc_feature_tsn_sr_flow_no_asf_select)) { 2308 mem = CUT_THROUGH_ATTRIBUTEm; 2309 sal_memset(&ct_entry, 0, sizeof(ct_entry)); 2310 v = (cfg->flags & BCM_TSN_SR_TX_FLOW_CONFIG_DO_NOT_CUT_THROUGH) ? 2311 1 : 0; 2312 soc_mem_field32_set(unit, mem, &ct_entry, DO_NOT_CUT_THROUGHf, v); 2313 rv = soc_mem_write(unit, mem, MEM_BLOCK_ALL, 2314 TSN_SRFLOWS_IDX_TO_HW_ID(1, idx), 2315 &ct_entry); 2316 if (SOC_FAILURE(rv)) { 2317 LOG_ERROR(BSL_LS_BCM_TSN, 2318 (BSL_META_U(unit, "Failed to write mem[%s]"), 2319 SOC_MEM_NAME(unit, mem))); 2320 return rv; 2321 } 2322 } else { 2323 if (cfg->flags & BCM_TSN_SR_TX_FLOW_CONFIG_DO_NOT_CUT_THROUGH) { 2324 LOG_VERBOSE(BSL_LS_BCM_TSN, 2325 (BSL_META_U(unit, 2326 "SR TX flow disable cut-through " 2327 "is not configurable\n"))); 2328 return BCM_E_PARAM; 2329 } 2330 } 2331 2332 /* Write to HW with HW index idx+1 since entry 0 is not visible to SW */ 2333 mem = SR_TXm; 2334 sal_memset(&entry, 0, sizeof(entry)); 2335 MEM_LOCK(unit, mem); 2336 rv = soc_mem_read(unit, mem, MEM_BLOCK_ANY, idx + 1, &entry); 2337 if (SOC_FAILURE(rv)) { 2338 LOG_ERROR(BSL_LS_BCM_TSN, 2339 (BSL_META_U(unit, "Failed to read mem[%s]"), 2340 SOC_MEM_NAME(unit, mem))); 2341 MEM_UNLOCK(unit, mem); 2342 return rv; 2343 } 2344 soc_mem_field32_set(unit, mem, &entry, NEXT_SNf, config->config.seq_num); 2345 rv = soc_mem_write(unit, mem, MEM_BLOCK_ALL, idx + 1, &entry); 2346 if (SOC_FAILURE(rv)) { 2347 LOG_ERROR(BSL_LS_BCM_TSN, 2348 (BSL_META_U(unit, "Failed to write mem[%s]"), 2349 SOC_MEM_NAME(unit, mem))); 2350 MEM_UNLOCK(unit, mem); 2351 return rv; 2352 } 2353 /* Unlock memory SR_TXm */ 2354 MEM_UNLOCK(unit, mem); 2355 2356 /* MTU profile id HW writing */ 2357 if (soc_feature(unit, soc_feature_tsn_mtu_stu)) { 2358 hw_id = (uint32)TSN_SRFLOWS_IDX_TO_HW_ID(is_tx, idx); 2359 mem = ING_MTU_CHECK_2m; 2360 sal_memset(&mtu_ent, 0, sizeof(mtu_ent)); 2361 MEM_LOCK(unit, mem); 2362 rv = soc_mem_read(unit, mem, MEM_BLOCK_ANY, hw_id, &mtu_ent); 2363 if (SOC_FAILURE(rv)) { 2364 LOG_ERROR(BSL_LS_BCM_TSN, 2365 (BSL_META_U(unit, "Failed to read mem[%s]"), 2366 SOC_MEM_NAME(unit, mem))); 2367 MEM_UNLOCK(unit, mem); 2368 return rv; 2369 } 2370 type = bcmTsnMtuProfileTypeIngress; 2371 rv = bcmi_gh2_tsn_mtu_profile_decode( 2372 unit, config->config.ingress_mtu_profile, 2373 &type, &mtu_hw_index); 2374 if (SOC_FAILURE(rv)) { 2375 LOG_ERROR(BSL_LS_BCM_TSN, 2376 (BSL_META_U(unit, "Failed to decode profile id[%d]"), 2377 config->config.ingress_mtu_profile)); 2378 MEM_UNLOCK(unit, mem); 2379 return rv; 2380 } 2381 soc_mem_field32_set(unit, mem, &mtu_ent, MTU_PROFILE_INDEXf, 2382 mtu_hw_index); 2383 rv = soc_mem_write(unit, mem, MEM_BLOCK_ALL, hw_id, &mtu_ent); 2384 if (SOC_FAILURE(rv)) { 2385 LOG_ERROR(BSL_LS_BCM_TSN, 2386 (BSL_META_U(unit, "Failed to write mem[%s]"), 2387 SOC_MEM_NAME(unit, mem))); 2388 MEM_UNLOCK(unit, mem); 2389 return rv; 2390 } 2391 /* Unlock memory ING_MTU_CHECK_2m */ 2392 MEM_UNLOCK(unit, mem); 2393 } 2394 2395 return BCM_E_NONE; 2396 } 2397 2398 #ifdef BCM_WARM_BOOT_SUPPORT 2399 /* SR flow mgmt - read flow config (for warm boot) */ 2400 STATIC int 2401 bcmi_gh2_tsn_sr_flows_read_rx_flow( 2402 int unit, 2403 int idx, 2404 bcmi_tsn_sr_rx_flow_t *config) 2405 { 2406 soc_mem_t mem; 2407 sr_rx_entry_t entry; 2408 cut_through_attribute_entry_t ct_entry; 2409 ing_mtu_check_2_entry_t mtu_ent; 2410 bcm_tsn_sr_rx_flow_config_t *cfg; 2411 tsn_sr_seqnum_slice_t *slice, *sn; 2412 uint32 power; 2413 uint32 v; 2414 int mtu_idx, mtu_id; 2415 int eidx; 2416 int offs; 2417 int rv; 2418 int i; 2419 2420 /* parameter check */ 2421 TSN_BKINFO_IS_INIT(unit); 2422 if (!soc_feature(unit, soc_feature_tsn_sr)) { 2423 return (BCM_E_UNAVAIL); 2424 } 2425 if (NULL == config || 2426 idx < 0 || idx >= SRFLOWS_BKINFO(unit).max_flows_rx) { 2427 return BCM_E_PARAM; 2428 } 2429 2430 /* This routine is for warm boot only */ 2431 if (!SOC_WARM_BOOT(unit)) { 2432 return BCM_E_UNAVAIL; 2433 } 2434 2435 /* Get config from HW with HW index idx+1 */ 2436 mem = SR_RXm; 2437 sal_memset(&entry, 0, sizeof(entry)); 2438 rv = soc_mem_read(unit, mem, MEM_BLOCK_ANY, idx + 1, &entry); 2439 if (SOC_FAILURE(rv)) { 2440 LOG_ERROR(BSL_LS_BCM_TSN, 2441 (BSL_META_U(unit, "Failed to read mem[%s]"), 2442 SOC_MEM_NAME(unit, mem))); 2443 return rv; 2444 } 2445 2446 /* Start compiling the configuration from HW values */ 2447 cfg = &config->config; 2448 2449 /* Flags */ 2450 cfg->flags = 0; 2451 if (soc_mem_field32_get(unit, mem, &entry, ACCEPT_DUPLICATE_PACKETf)) { 2452 cfg->flags |= BCM_TSN_SR_RX_FLOW_CONFIG_ACCEPT_DUPLICATES; 2453 } 2454 if (soc_mem_field32_get(unit, mem, &entry, ACCEPT_IN_DROP_WINDOWf)) { 2455 cfg->flags |= BCM_TSN_SR_RX_FLOW_CONFIG_ACCEPT_PKT_IN_DROP_WINDOW; 2456 } 2457 if (soc_mem_field32_get(unit, mem, &entry, DROP_OUT_OF_ORDERf)) { 2458 cfg->flags |= BCM_TSN_SR_RX_FLOW_CONFIG_DROP_OUT_OF_ORDER; 2459 } 2460 2461 /* Acceptance window */ 2462 v = soc_mem_field32_get(unit, mem, &entry, ACCEPTANCE_WINDOW_SIZEf); 2463 power = TSN_SRFLOWS_RX_ACCEPT_POWER_MAX - v; 2464 if (power < TSN_SRFLOWS_RX_ACCEPT_POWER_MIN || 2465 power > TSN_SRFLOWS_RX_ACCEPT_POWER_MAX) { 2466 return BCM_E_INTERNAL; 2467 } 2468 assert(power < sizeof(tsn_math_powers) / sizeof(int)); 2469 cfg->seqnum_accept_win_size = (uint32)tsn_math_powers[power]; 2470 2471 /* Sequence number history window size */ 2472 v = soc_mem_field32_get(unit, mem, &entry, SN_WINDOW_SIZEf); 2473 if (v == 0) { 2474 cfg->seqnum_history_win_size = 1; 2475 } else { 2476 power = v + TSN_SRFLOWS_RX_WINDOW_POWER_MIN - 1; 2477 if (power < TSN_SRFLOWS_RX_WINDOW_POWER_MIN || 2478 power > TSN_SRFLOWS_RX_WINDOW_POWER_MAX) { 2479 return BCM_E_INTERNAL; 2480 } 2481 assert(power < sizeof(tsn_math_powers) / sizeof(int)); 2482 cfg->seqnum_history_win_size = (uint32)tsn_math_powers[power]; 2483 } 2484 2485 /* Age out time interval */ 2486 v = soc_mem_field32_get(unit, mem, &entry, SN_AGE_OUT_ENABLEf); 2487 if (v == 0) { 2488 cfg->age_timeout = 0; 2489 } else { 2490 power = soc_mem_field32_get(unit, mem, &entry, AGE_OUT_MULTIPLIERf); 2491 assert(power < sizeof(tsn_math_powers) / sizeof(int)); 2492 cfg->age_timeout = (uint32)tsn_math_powers[power]; 2493 } 2494 2495 /* Re-build SN slices */ 2496 sn = NULL; 2497 for (i = 0; i < TSN_SRFLOWS_RX_SN_HIST_POOLS; i++) { 2498 v = soc_mem_field32_get(unit, mem, &entry, tsn_flow_sr_hist_sizes[i]); 2499 if (v != 0 && v != 1) { 2500 eidx = (int)soc_mem_field32_get( 2501 unit, mem, &entry, tsn_flow_sr_hist_indexs[i]); 2502 offs = (int)soc_mem_field32_get( 2503 unit, mem, &entry, tsn_flow_sr_hist_offsets[i]); 2504 rv = bcmi_gh2_tsn_sr_flows_seqnum_slice_wb_restore( 2505 unit, 2506 i, 2507 eidx, 2508 offs * TSN_SRFLOWS_RX_SN_HIST_BLOCK_SIZE, 2509 v - 2 + TSN_SRFLOWS_RX_SNPOOL_POWER_MIN, 2510 &slice 2511 ); 2512 if (rv != BCM_E_NONE) { 2513 if (sn != NULL) { 2514 (void)bcmi_gh2_tsn_sr_flows_seqnum_slice_free( 2515 unit, (bcmi_tsn_sr_seqnum_slice_t)sn); 2516 } 2517 return rv; 2518 } 2519 if (slice != NULL) { 2520 slice->next = sn; 2521 sn = slice; 2522 } else { 2523 assert(0); 2524 return BCM_E_INTERNAL; 2525 } 2526 } 2527 } 2528 config->sn_slice = (bcmi_tsn_sr_seqnum_slice_t)sn; 2529 2530 /* Get flag from hardware */ 2531 mem = CUT_THROUGH_ATTRIBUTEm; 2532 sal_memset(&ct_entry, 0, sizeof(ct_entry)); 2533 rv = soc_mem_read(unit, mem, MEM_BLOCK_ANY, 2534 TSN_SRFLOWS_IDX_TO_HW_ID(0, idx), &ct_entry); 2535 if (SOC_FAILURE(rv)) { 2536 LOG_ERROR(BSL_LS_BCM_TSN, 2537 (BSL_META_U(unit, "Failed to read mem[%s]"), 2538 SOC_MEM_NAME(unit, mem))); 2539 return rv; 2540 } 2541 if (soc_mem_field32_get(unit, mem, &ct_entry, DO_NOT_CUT_THROUGHf)) { 2542 cfg->flags |= BCM_TSN_SR_RX_FLOW_CONFIG_DO_NOT_CUT_THROUGH; 2543 } 2544 /* MTU SR rx flow warm boot read */ 2545 if (soc_feature(unit, soc_feature_tsn_mtu_stu)) { 2546 mem = ING_MTU_CHECK_2m; 2547 2548 sal_memset(&mtu_ent, 0, sizeof(mtu_ent)); 2549 rv = soc_mem_read(unit, mem, MEM_BLOCK_ANY, 2550 TSN_SRFLOWS_IDX_TO_HW_ID(0, idx), &mtu_ent); 2551 if (SOC_FAILURE(rv)) { 2552 LOG_ERROR(BSL_LS_BCM_TSN, 2553 (BSL_META_U(unit, "Failed to read mem[%s]"), 2554 SOC_MEM_NAME(unit, mem))); 2555 return rv; 2556 } 2557 mtu_idx = soc_mem_field32_get(unit, mem, &mtu_ent, MTU_PROFILE_INDEXf); 2558 rv = bcmi_gh2_tsn_mtu_profile_encode(unit, mtu_idx, 2559 bcmTsnMtuProfileTypeIngress, 2560 &mtu_id); 2561 if (SOC_FAILURE(rv)) { 2562 LOG_ERROR(BSL_LS_BCM_TSN, 2563 (BSL_META_U(unit, "Failed to encode mtu profile" 2564 " from idx = %d"), mtu_idx)); 2565 return rv; 2566 } 2567 cfg->ingress_mtu_profile = mtu_id; 2568 } 2569 2570 return BCM_E_NONE; 2571 } 2572 2573 /* SR flow mgmt - read flow config (for warm boot) */ 2574 STATIC int 2575 bcmi_gh2_tsn_sr_flows_read_tx_flow( 2576 int unit, 2577 int idx, 2578 bcmi_tsn_sr_tx_flow_t *config) 2579 { 2580 soc_mem_t mem; 2581 sr_tx_entry_t entry; 2582 cut_through_attribute_entry_t ct_entry; 2583 ing_mtu_check_2_entry_t mtu_ent; 2584 int mtu_idx, mtu_id; 2585 int rv; 2586 2587 /* parameter check */ 2588 TSN_BKINFO_IS_INIT(unit); 2589 if (!soc_feature(unit, soc_feature_tsn_sr)) { 2590 return (BCM_E_UNAVAIL); 2591 } 2592 if (NULL == config || 2593 idx < 0 || idx >= SRFLOWS_BKINFO(unit).max_flows_tx) { 2594 return BCM_E_PARAM; 2595 } 2596 2597 /* This routine is for warm boot only */ 2598 if (!SOC_WARM_BOOT(unit)) { 2599 return BCM_E_UNAVAIL; 2600 } 2601 2602 /* Get config from HW with HW index idx+1 */ 2603 mem = SR_TXm; 2604 sal_memset(&entry, 0, sizeof(entry)); 2605 rv = soc_mem_read(unit, mem, MEM_BLOCK_ANY, idx + 1, &entry); 2606 if (SOC_FAILURE(rv)) { 2607 LOG_ERROR(BSL_LS_BCM_TSN, 2608 (BSL_META_U(unit, "Failed to read mem[%s]"), 2609 SOC_MEM_NAME(unit, mem))); 2610 return rv; 2611 } 2612 config->config.seq_num = soc_mem_field32_get(unit, mem, &entry, NEXT_SNf); 2613 2614 /* Get config from hardware */ 2615 mem = CUT_THROUGH_ATTRIBUTEm; 2616 sal_memset(&ct_entry, 0, sizeof(ct_entry)); 2617 rv = soc_mem_read(unit, mem, MEM_BLOCK_ANY, 2618 TSN_SRFLOWS_IDX_TO_HW_ID(1, idx), &ct_entry); 2619 if (SOC_FAILURE(rv)) { 2620 LOG_ERROR(BSL_LS_BCM_TSN, 2621 (BSL_META_U(unit, "Failed to read mem[%s]"), 2622 SOC_MEM_NAME(unit, mem))); 2623 return rv; 2624 } 2625 if (soc_mem_field32_get(unit, mem, &ct_entry, DO_NOT_CUT_THROUGHf)) { 2626 config->config.flags |= BCM_TSN_SR_TX_FLOW_CONFIG_DO_NOT_CUT_THROUGH; 2627 } 2628 /* MTU SR tx flow warm boot read */ 2629 if (soc_feature(unit, soc_feature_tsn_mtu_stu)) { 2630 mem = ING_MTU_CHECK_2m; 2631 2632 sal_memset(&mtu_ent, 0, sizeof(mtu_ent)); 2633 rv = soc_mem_read(unit, mem, MEM_BLOCK_ANY, 2634 TSN_SRFLOWS_IDX_TO_HW_ID(1, idx), &mtu_ent); 2635 if (SOC_FAILURE(rv)) { 2636 LOG_ERROR(BSL_LS_BCM_TSN, 2637 (BSL_META_U(unit, "Failed to read mem[%s]"), 2638 SOC_MEM_NAME(unit, mem))); 2639 return rv; 2640 } 2641 mtu_idx = soc_mem_field32_get(unit, mem, &mtu_ent, MTU_PROFILE_INDEXf); 2642 rv = bcmi_gh2_tsn_mtu_profile_encode(unit, mtu_idx, 2643 bcmTsnMtuProfileTypeIngress, 2644 &mtu_id); 2645 if (SOC_FAILURE(rv)) { 2646 LOG_ERROR(BSL_LS_BCM_TSN, 2647 (BSL_META_U(unit, "Failed to encode mtu profile" 2648 " from idx = %d"), mtu_idx)); 2649 return rv; 2650 } 2651 config->config.ingress_mtu_profile = mtu_id; 2652 } 2653 2654 return BCM_E_NONE; 2655 } 2656 #endif /* BCM_WARM_BOOT_SUPPORT */ 2657 2658 /* SR flow mgmt - get flow status */ 2659 STATIC int 2660 bcmi_gh2_tsn_sr_flows_get_tx_flow_status( 2661 int unit, 2662 int idx, 2663 bcm_tsn_sr_tx_flow_status_t *status) 2664 { 2665 soc_mem_t mem; 2666 sr_tx_entry_t entry; 2667 int rv; 2668 2669 /* parameter check */ 2670 TSN_BKINFO_IS_INIT(unit); 2671 if (!soc_feature(unit, soc_feature_tsn_sr)) { 2672 return (BCM_E_UNAVAIL); 2673 } 2674 if (NULL == status || 2675 idx < 0 || idx >= SRFLOWS_BKINFO(unit).max_flows_tx) { 2676 return BCM_E_PARAM; 2677 } 2678 2679 /* Get status from HW with HW index idx+1 */ 2680 mem = SR_TXm; 2681 sal_memset(&entry, 0, sizeof(entry)); 2682 rv = soc_mem_read(unit, mem, MEM_BLOCK_ANY, idx + 1, &entry); 2683 if (SOC_FAILURE(rv)) { 2684 LOG_ERROR(BSL_LS_BCM_TSN, 2685 (BSL_META_U(unit, "Failed to read mem[%s]"), 2686 SOC_MEM_NAME(unit, mem))); 2687 return rv; 2688 } 2689 status->seq_num = soc_mem_field32_get(unit, mem, &entry, NEXT_SNf); 2690 2691 return BCM_E_NONE; 2692 } 2693 2694 /* SR flow mgmt - get flow status */ 2695 STATIC int 2696 bcmi_gh2_tsn_sr_flows_get_rx_flow_status( 2697 int unit, 2698 int idx, 2699 bcm_tsn_sr_rx_flow_status_t *status) 2700 { 2701 soc_mem_t mem; 2702 sr_rx_entry_t entry; 2703 int rv; 2704 2705 /* parameter check */ 2706 TSN_BKINFO_IS_INIT(unit); 2707 if (!soc_feature(unit, soc_feature_tsn_sr)) { 2708 return (BCM_E_UNAVAIL); 2709 } 2710 if (NULL == status || 2711 idx < 0 || idx >= SRFLOWS_BKINFO(unit).max_flows_rx) { 2712 return BCM_E_PARAM; 2713 } 2714 2715 /* Get status from HW with HW index idx+1 */ 2716 mem = SR_RXm; 2717 sal_memset(&entry, 0, sizeof(entry)); 2718 rv = soc_mem_read(unit, mem, MEM_BLOCK_ANY, idx + 1, &entry); 2719 if (SOC_FAILURE(rv)) { 2720 LOG_ERROR(BSL_LS_BCM_TSN, 2721 (BSL_META_U(unit, "Failed to read mem[%s]"), 2722 SOC_MEM_NAME(unit, mem))); 2723 return rv; 2724 } 2725 status->seqnum_win_in_reset = 2726 (int)soc_mem_field32_get(unit, mem, &entry, SN_RESET_STATEf); 2727 status->seqnum_age_countdown = 2728 (int)soc_mem_field32_get(unit, mem, &entry, SN_AGE_OUT_COUNT_DOWNf); 2729 status->last_history_win_seqnum = 2730 soc_mem_field32_get(unit, mem, &entry, LAST_WINDOW_SNf); 2731 status->last_accepted_seqnum_lan[0] = 2732 soc_mem_field32_get(unit, mem, &entry, LAST_RECEIVED_SN_LAN_Af); 2733 status->last_accepted_seqnum_lan[1] = 2734 soc_mem_field32_get(unit, mem, &entry, LAST_RECEIVED_SN_LAN_Bf); 2735 status->wrong_lan[0] = 2736 (int)soc_mem_field32_get(unit, mem, &entry, WRONG_LAN_Af); 2737 status->wrong_lan[1] = 2738 (int)soc_mem_field32_get(unit, mem, &entry, WRONG_LAN_Bf); 2739 status->wrong_lan_age_countdown[0] = (int)soc_mem_field32_get( 2740 unit, mem, &entry, WRONG_LAN_A_AGE_OUT_COUNT_DOWNf); 2741 status->wrong_lan_age_countdown[1] = (int)soc_mem_field32_get( 2742 unit, mem, &entry, WRONG_LAN_B_AGE_OUT_COUNT_DOWNf); 2743 2744 return BCM_E_NONE; 2745 } 2746 2747 /* 2748 * Function: 2749 * bcmi_gh2_tsn_sr_port_config_get 2750 * Purpose: 2751 * Get SR configuration from a port 2752 * Parameters: 2753 * unit - (IN) unit number 2754 * port - (IN) port 2755 * config - (OUT) port SR configuration 2756 * Returns: 2757 * BCM_E_XXX 2758 * Notes: 2759 */ 2760 STATIC int 2761 bcmi_gh2_tsn_sr_port_config_get( 2762 int unit, 2763 bcm_gport_t gport, 2764 bcm_tsn_sr_port_config_t *config) 2765 { 2766 bcm_port_t port; 2767 sr_port_table_entry_t sr_port_ent; 2768 soc_mem_t mem; 2769 int rv = BCM_E_NONE; 2770 uint32 val; 2771 2772 /* Parameter check */ 2773 if (config == NULL) { 2774 return BCM_E_PARAM; 2775 } 2776 2777 /* Validate and convert gport to local port */ 2778 BCM_IF_ERROR_RETURN( 2779 _bcm_esw_port_gport_validate(unit, gport, &port)); 2780 2781 /* Initialize the data first */ 2782 bcm_tsn_sr_port_config_t_init(config); 2783 2784 /* Use PORT_TAB as major reference since all others should be the same */ 2785 mem = SR_PORT_TABLEm; 2786 rv = soc_mem_read(unit, mem, MEM_BLOCK_ANY, port, &sr_port_ent); 2787 if (BCM_FAILURE(rv)) { 2788 return rv; 2789 } 2790 2791 /* Check if SR enabled */ 2792 val = soc_mem_field32_get( 2793 unit, mem, &sr_port_ent, ING_SR_ENABLEf); 2794 if (val) { 2795 /* SR port type */ 2796 val = soc_mem_field32_get(unit, mem, &sr_port_ent, ING_SR_TYPEf); 2797 config->port_type = (bcm_tsn_sr_port_type_t)(val + 1); 2798 2799 /* Interlink role */ 2800 val = soc_mem_field32_get(unit, mem, &sr_port_ent, ING_SR_PORT_ROLEf); 2801 config->interlink_role = val ? 0 : 1; 2802 2803 /* sr mode */ 2804 config->port_mode = (bcm_tsn_sr_port_mode_t) 2805 soc_mem_field32_get(unit, mem, &sr_port_ent, ING_SR_MODEf); 2806 2807 /* LAN ID */ 2808 config->lan_id = (uint8) 2809 soc_mem_field32_get(unit, mem, &sr_port_ent, ING_SR_LAN_IDf); 2810 2811 /* NET ID */ 2812 config->net_id = (uint8) 2813 soc_mem_field32_get(unit, mem, &sr_port_ent, ING_SR_NET_IDf); 2814 2815 /* mac_da_flows */ 2816 val = soc_mem_field32_get( 2817 unit, mem, &sr_port_ent, FLOW_ID_SOURCE_PRIORITYf); 2818 config->mac_da_flows = val ? 1 : 0; 2819 } else { 2820 /* SR disabled */ 2821 config->port_type = bcmTsnSrPortTypeNone; 2822 } 2823 2824 return BCM_E_NONE; 2825 } 2826 2827 /* 2828 * SR port stub for config set to support Modified-PRP configuration. 2829 * Note: Use port_type=bcmTsnSrPortTypeCount to configure Modified-PRP port 2830 */ 2831 STATIC int 2832 bcmi_gh2_tsn_sr_port_config_apply( 2833 int unit, 2834 bcm_port_t port, 2835 bcm_tsn_sr_port_config_t *ori_config, 2836 bcm_tsn_sr_port_config_t *new_config) 2837 { 2838 soc_mem_t mem; 2839 uint32 entry[SOC_MAX_MEM_WORDS]; 2840 soc_field_t fld; 2841 uint32 val; 2842 int ptab; 2843 bcm_trunk_t trunk_id; 2844 int rv; 2845 2846 /* Port tables to write */ 2847 const soc_mem_t mem_list[] = { 2848 SR_PORT_TABLEm, 2849 SR_LPORT_TABm, 2850 SR_ING_EGR_PORTm, 2851 SR_ING_EGR_TRUNKm, 2852 SR_EGR_PORTm, 2853 SR_EGR_ING_PORTm 2854 }; 2855 2856 /* Fields for different port tables */ 2857 const soc_field_t fields_sr_enable[] = { 2858 ING_SR_ENABLEf, 2859 ING_SR_ENABLEf, 2860 EGR_SR_ENABLEf, 2861 EGR_SR_ENABLEf, 2862 EGR_SR_ENABLEf, 2863 ING_SR_ENABLEf 2864 }; 2865 const soc_field_t fields_sr_type[] = { 2866 ING_SR_TYPEf, 2867 ING_SR_TYPEf, 2868 EGR_SR_TYPEf, 2869 EGR_SR_TYPEf, 2870 EGR_SR_TYPEf, 2871 ING_SR_TYPEf 2872 }; 2873 const soc_field_t fields_sr_role[] = { 2874 ING_SR_PORT_ROLEf, 2875 ING_SR_PORT_ROLEf, 2876 EGR_SR_PORT_ROLEf, 2877 EGR_SR_PORT_ROLEf, 2878 EGR_SR_PORT_ROLEf, 2879 ING_SR_PORT_ROLEf 2880 }; 2881 const soc_field_t fields_sr_mode[] = { 2882 ING_SR_MODEf, 2883 ING_SR_MODEf, 2884 EGR_SR_MODEf, 2885 EGR_SR_MODEf, 2886 EGR_SR_MODEf, 2887 ING_SR_MODEf 2888 }; 2889 const soc_field_t fields_sr_lanid[] = { 2890 ING_SR_LAN_IDf, 2891 ING_SR_LAN_IDf, 2892 EGR_SR_LAN_IDf, 2893 EGR_SR_LAN_IDf, 2894 EGR_SR_LAN_IDf, 2895 ING_SR_LAN_IDf 2896 }; 2897 const soc_field_t fields_sr_netid[] = { 2898 ING_SR_NET_IDf, 2899 ING_SR_NET_IDf, 2900 EGR_SR_NET_IDf, 2901 EGR_SR_NET_IDf, 2902 EGR_SR_NET_IDf, 2903 ING_SR_NET_IDf 2904 }; 2905 const soc_field_t fields_sr_flowsrc[] = { 2906 FLOW_ID_SOURCE_PRIORITYf, 2907 FLOW_ID_SOURCE_PRIORITYf, 2908 INVALIDf, 2909 INVALIDf, 2910 INVALIDf, 2911 INVALIDf 2912 }; 2913 int mem_idx; 2914 bcm_module_t my_modid = -1; 2915 int src_trk_idx = 0; /* Source Trunk table index.*/ 2916 uint32 mem_entry[SOC_MAX_MEM_WORDS]; 2917 2918 BCM_IF_ERROR_RETURN(bcm_esw_stk_my_modid_get(unit, &my_modid)); 2919 2920 assert(NULL != ori_config && NULL != new_config); 2921 2922 /* Update HW only if it's changed */ 2923 if (!sal_memcmp(ori_config, new_config, sizeof(*ori_config))) { 2924 return BCM_E_NONE; 2925 } 2926 2927 /* Apply to all the port tables */ 2928 for (ptab = 0; ptab < COUNTOF(mem_list); ptab++) { 2929 mem = mem_list[ptab]; 2930 2931 if (mem == SR_LPORT_TABm) { 2932 BCM_IF_ERROR_RETURN( 2933 _bcm_esw_src_mod_port_table_index_get(unit, my_modid, 2934 port, &src_trk_idx)); 2935 2936 BCM_IF_ERROR_RETURN( 2937 soc_mem_read(unit, SOURCE_TRUNK_MAP_TABLEm, MEM_BLOCK_ANY, 2938 src_trk_idx, mem_entry)); 2939 2940 mem_idx = soc_mem_field32_get(unit, SOURCE_TRUNK_MAP_TABLEm, 2941 mem_entry, LPORT_PROFILE_IDXf); 2942 } else if (mem == SR_ING_EGR_TRUNKm) { 2943 /* Check if the port belongs to a trunk */ 2944 rv = bcm_esw_trunk_find(unit, my_modid, port, &trunk_id); 2945 if (BCM_SUCCESS(rv)) { 2946 /* Port is member of a valid trunk */ 2947 mem_idx = trunk_id; 2948 } else { 2949 /* Port is not member of any valid trunk */ 2950 continue; 2951 } 2952 } else { 2953 mem_idx = port; 2954 } 2955 /* Read the original entry for modification */ 2956 sal_memset(entry, 0, sizeof(entry)); 2957 BCM_IF_ERROR_RETURN( 2958 soc_mem_read(unit, mem, MEM_BLOCK_ANY, mem_idx, entry)); 2959 2960 /* Check SR enable */ 2961 if (new_config->port_type == bcmTsnSrPortTypeNone) { 2962 /* 2963 * SR disabled: just write SR_ENABLE and all other fields are 0 2964 */ 2965 2966 /* SR enable = 0 */ 2967 fld = fields_sr_enable[ptab]; 2968 val = 0; 2969 soc_mem_field32_set(unit, mem, entry, fld, val); 2970 } else { 2971 /* 2972 * SR enabled: write configuration and enable it at last 2973 */ 2974 2975 /* SR type */ 2976 fld = fields_sr_type[ptab]; 2977 val = new_config->port_type - 1; 2978 soc_mem_field32_set(unit, mem, entry, fld, val); 2979 2980 /* SR role */ 2981 fld = fields_sr_role[ptab]; 2982 val = new_config->interlink_role ? 0 : 1; 2983 soc_mem_field32_set(unit, mem, entry, fld, val); 2984 2985 /* SR mode */ 2986 fld = fields_sr_mode[ptab]; 2987 val = new_config->port_mode; 2988 soc_mem_field32_set(unit, mem, entry, fld, val); 2989 2990 /* SR LAN ID */ 2991 fld = fields_sr_lanid[ptab]; 2992 val = new_config->lan_id; 2993 soc_mem_field32_set(unit, mem, entry, fld, val); 2994 2995 /* SR NET ID */ 2996 fld = fields_sr_netid[ptab]; 2997 val = new_config->net_id; 2998 soc_mem_field32_set(unit, mem, entry, fld, val); 2999 3000 /* SR flow ID source priority (not for all tables) */ 3001 fld = fields_sr_flowsrc[ptab]; 3002 if (fld != INVALIDf) { 3003 val = new_config->mac_da_flows ? 1 : 0; 3004 soc_mem_field32_set(unit, mem, entry, fld, val); 3005 } 3006 3007 /* Write SR enable at last */ 3008 fld = fields_sr_enable[ptab]; 3009 val = 1; 3010 soc_mem_field32_set(unit, mem, entry, fld, val); 3011 } 3012 3013 /* Write the new configuration */ 3014 BCM_IF_ERROR_RETURN( 3015 soc_mem_write(unit, mem, MEM_BLOCK_ALL, mem_idx, entry)); 3016 } 3017 3018 return BCM_E_NONE; 3019 } 3020 3021 /* SR PRP port forwarding: callback for destroying customer header match */ 3022 STATIC int 3023 bcmi_gh2_tsn_sr_port_prp_forwarding_destroy_switch_match( 3024 int unit, 3025 int match_id, 3026 bcm_switch_match_config_info_t *config_info, 3027 void *user_data) 3028 { 3029 bcm_port_t prp_port; 3030 3031 if (NULL == user_data || NULL == config_info) { 3032 return BCM_E_INTERNAL; /* should not happen */ 3033 } 3034 3035 prp_port = *((bcm_port_t *)user_data); 3036 if (config_info->value32 == PRP_FORWARDING_CH_ENCAP_VALUE(0, prp_port) || 3037 config_info->value32 == PRP_FORWARDING_CH_ENCAP_VALUE(1, prp_port)) { 3038 uint32 match_id_hw; 3039 bcm_switch_match_service_t match_service; 3040 3041 /* need to clean PRP_PACKETf LPORT_PROFILE_IDXf by ourselves */ 3042 BCM_IF_ERROR_RETURN( 3043 bcmi_switch_match_hw_id_get( 3044 unit, match_id, &match_service, &match_id_hw)); 3045 if (bcmSwitchMatchServiceCustomHeader != match_service) { 3046 BCM_IF_ERROR_RETURN(BCM_E_INTERNAL); 3047 } 3048 BCM_IF_ERROR_RETURN( 3049 soc_mem_field32_modify( 3050 unit, CUSTOM_HEADER_POLICY_TABLEm, match_id_hw, 3051 PRP_PACKETf, 0)); 3052 BCM_IF_ERROR_RETURN( 3053 soc_mem_field32_modify( 3054 unit, CUSTOM_HEADER_POLICY_TABLEm, match_id_hw, 3055 LPORT_PROFILE_IDXf, 0)); 3056 3057 /* invoke API to delete switch_match */ 3058 BCM_IF_ERROR_RETURN( 3059 bcm_esw_switch_match_config_delete( 3060 unit, bcmSwitchMatchServiceCustomHeader, match_id)); 3061 } 3062 3063 return BCM_E_NONE; 3064 } 3065 3066 /* SR PRP port forwarding: callback for destroying customer header encap */ 3067 STATIC int 3068 bcmi_gh2_tsn_sr_port_prp_forwarding_destroy_switch_encap( 3069 int unit, 3070 bcm_if_t encap_id, 3071 bcm_switch_encap_info_t *encap_info, 3072 void *user_data) 3073 { 3074 bcm_port_t prp_port; 3075 3076 if (NULL == user_data || NULL == encap_info) { 3077 return BCM_E_INTERNAL; /* should not happen */ 3078 } 3079 3080 prp_port = *((bcm_port_t *)user_data); 3081 if (encap_info->value32 == PRP_FORWARDING_CH_ENCAP_VALUE(0, prp_port) || 3082 encap_info->value32 == PRP_FORWARDING_CH_ENCAP_VALUE(1, prp_port)) { 3083 BCM_IF_ERROR_RETURN( 3084 bcm_esw_switch_encap_destroy(unit, encap_id)); 3085 } 3086 3087 return BCM_E_NONE; 3088 } 3089 3090 3091 /* helper function to remove all ifp rules that created on this specific port */ 3092 STATIC int 3093 bcmi_gh2_tsn_sr_remove_all_field_entries( 3094 int unit, 3095 bcm_field_group_t field_group, 3096 bcm_port_t target_port) 3097 { 3098 int ifp_group_entry_num; 3099 bcm_field_entry_t *ifp_group_entry_array = NULL; 3100 int ifp_group_entry_array_size; 3101 int i; 3102 3103 /* 1st time to get the array size that we need */ 3104 PRP_FORWARDING_ERROR_RETURN( 3105 bcm_esw_field_entry_multi_get( 3106 unit, PRP_FORWARDING_REDIRECT_GROUP(unit), 0, 3107 NULL, &ifp_group_entry_num)); 3108 3109 ifp_group_entry_array_size = ifp_group_entry_num; 3110 ifp_group_entry_array = (bcm_field_entry_t *) 3111 sal_alloc(sizeof(bcm_field_entry_t) * ifp_group_entry_array_size, 3112 "ifp_group_entry_array"); 3113 if (NULL == ifp_group_entry_array) { 3114 PRP_FORWARDING_ERROR_RETURN(BCM_E_MEMORY); 3115 } 3116 3117 /* 2nd time to get all entries to the array that we just allocated */ 3118 PRP_FORWARDING_ERROR_RETURN_WITH_CLEAN( 3119 bcm_esw_field_entry_multi_get( 3120 unit, PRP_FORWARDING_REDIRECT_GROUP(unit), 3121 ifp_group_entry_array_size, 3122 ifp_group_entry_array, &ifp_group_entry_num), 3123 sal_free(ifp_group_entry_array)); 3124 assert(ifp_group_entry_num == ifp_group_entry_array_size); 3125 3126 /* remove the entries that qulified on this specific target port */ 3127 for (i = 0; i < ifp_group_entry_array_size; i++) { 3128 bcm_port_t data = 0, mask = 0; 3129 3130 PRP_FORWARDING_ERROR_RETURN_WITH_CLEAN( 3131 bcm_esw_field_qualify_InPort_get( 3132 unit, ifp_group_entry_array[i], &data, &mask), 3133 sal_free(ifp_group_entry_array)); 3134 if (data == target_port) { 3135 PRP_FORWARDING_ERROR_RETURN_WITH_CLEAN( 3136 bcm_esw_field_entry_remove( 3137 unit, ifp_group_entry_array[i]), 3138 sal_free(ifp_group_entry_array)); 3139 PRP_FORWARDING_ERROR_RETURN_WITH_CLEAN( 3140 bcm_esw_field_entry_destroy( 3141 unit, ifp_group_entry_array[i]), 3142 sal_free(ifp_group_entry_array)); 3143 break; 3144 } 3145 } 3146 sal_free(ifp_group_entry_array); 3147 ifp_group_entry_array = NULL; 3148 3149 return BCM_E_NONE; 3150 } 3151 3152 3153 /* SR PRP port forwarding: cancel prp forwarding at specific port */ 3154 STATIC void 3155 bcmi_gh2_tsn_sr_port_prp_forwarding_destroy( 3156 int unit, 3157 bcm_port_t prp_port) 3158 { 3159 /* destroy IFP rule on this prp port 3160 * : we traverse each entry in IFP group 3161 * delete it if this entry qualify this specified prp_port 3162 */ 3163 assert(PRP_FORWARDING_REDIRECT_GROUP_INVALID != 3164 PRP_FORWARDING_REDIRECT_GROUP(unit)); 3165 PRP_FORWARDING_DESTROY_ERROR_RETURN( 3166 bcmi_gh2_tsn_sr_remove_all_field_entries( 3167 unit, PRP_FORWARDING_REDIRECT_GROUP(unit), prp_port)); 3168 3169 /* cleanup CustomHeader match and policy */ 3170 PRP_FORWARDING_DESTROY_ERROR_RETURN( 3171 bcm_esw_switch_match_config_traverse( 3172 unit, bcmSwitchMatchServiceCustomHeader, 3173 bcmi_gh2_tsn_sr_port_prp_forwarding_destroy_switch_match, 3174 (void *)&prp_port)); 3175 3176 /* cleanup CustomHeader encap */ 3177 PRP_FORWARDING_DESTROY_ERROR_RETURN( 3178 bcm_esw_switch_encap_traverse( 3179 unit, 3180 bcmi_gh2_tsn_sr_port_prp_forwarding_destroy_switch_encap, 3181 (void *)&prp_port)); 3182 3183 } 3184 3185 /* 3186 * SR PRP port forwarding: setup prp forwarding at specific port 3187 * 3188 * Note 3189 * 1. Two encacp entries(CH1 and CH2) for this PRP port 3190 * - CH1 is for Non-PRP CustomHeader and CH2 is for PRP CustomHeader. 3191 * - API returned encap_id for CH1 is N and CH2's encap_id must be N + 1 3192 * >> HW behavior assert CH1 and CH2 encacp entries is continued. 3193 * 2. CustomHeader is expected will be engaged for PRP support only on the 3194 * GH2 device declared TSN-SR for PRP is supported. 3195 * - Thus two CustomHeader encap table entries directly mapped for 3196 * assigned PRP port. 3197 * >> CH1 entry : encacp_id = CustomHeader_type || prp_port * 2 3198 * >> CH2 entry : encacp_id = CustomHeader_type || prp_port * 2 + 1 3199 * 3. One IFP rule for PRP-Port encacp on CH1(1st entry) and the HW 3200 * automatically select the 2nd entry for CH2. 3201 * 4. two CustomHeader Match/Policy entries required for PRP_Port (no 3202 * assertion on continued entries in HW). 3203 * >> SW apply two entries as continued as well. 3204 */ 3205 STATIC int 3206 bcmi_gh2_tsn_sr_port_prp_forwarding_create( 3207 int unit, 3208 bcm_port_t prp_port) 3209 { 3210 bcm_field_entry_t fp_entry; 3211 bcm_if_t encap_id_prp, encap_id_non_prp; 3212 bcm_switch_encap_info_t encap_info; 3213 int match_id_prp, match_id_non_prp; 3214 int i; 3215 int lport_profile_idx; 3216 bcm_module_t my_modid = -1; 3217 int src_trk_idx = 0; /* Source Trunk table index.*/ 3218 uint32 mem_entry[SOC_MAX_MEM_WORDS]; 3219 3220 BCM_IF_ERROR_RETURN( 3221 bcm_esw_stk_my_modid_get(unit, &my_modid)); 3222 3223 /* setup switch_match on lb_port if 1st time to create prp port */ 3224 if (0 == PRP_FORWARDING_SWITCH_INIT(unit)) { 3225 bcm_switch_match_control_info_t match_control_info; 3226 3227 /* enable CustomHeader match/encap on loopbcak port 3228 * Note. because tsn module is inited before switch module 3229 * so we let switch_match_control setup at 1st prp-port create 3230 */ 3231 bcm_switch_match_control_info_t_init(&match_control_info); 3232 match_control_info.port_enable = TRUE; 3233 match_control_info.mask32 = PRP_FORWARDING_CH_HEADER_MASK; 3234 PRP_FORWARDING_CREATE_ERROR_RETURN( 3235 bcm_esw_switch_match_control_set( 3236 unit, bcmSwitchMatchServiceCustomHeader, 3237 bcmSwitchMatchControlPortEnable, 3238 PRP_FORWARDING_REDIRECT_GPORT(unit), &match_control_info)); 3239 3240 PRP_FORWARDING_CREATE_ERROR_RETURN( 3241 bcm_esw_switch_match_control_set( 3242 unit, bcmSwitchMatchServiceCustomHeader, 3243 bcmSwitchMatchControlMatchMask, 3244 PRP_FORWARDING_REDIRECT_GPORT(unit), &match_control_info)); 3245 3246 PRP_FORWARDING_CREATE_ERROR_RETURN( 3247 bcm_esw_port_control_set( 3248 unit, PRP_FORWARDING_REDIRECT_PORT(unit), 3249 bcmPortControlCustomHeaderEncapEnable, TRUE)); 3250 3251 PRP_FORWARDING_SWITCH_INIT(unit) = 1; 3252 } 3253 3254 /* create two CustomHeader encap : 3255 * step 1. create two continuous encap id 3256 * (with the same encap value for non-prp at first) 3257 * step 2. set 2nd encap id as prp value 3258 */ 3259 bcm_switch_encap_info_t_init(&encap_info); 3260 encap_info.encap_service = BCM_SWITCH_ENCAP_SERVICE_CUSTOM_HEADER; 3261 encap_info.value32 = PRP_FORWARDING_CH_ENCAP_VALUE(1, prp_port); 3262 PRP_FORWARDING_CREATE_ERROR_RETURN( 3263 _bcm_hr3_switch_encap_create( 3264 unit, &encap_info, 2, &encap_id_non_prp)); 3265 3266 encap_id_prp = encap_id_non_prp + 1; 3267 encap_info.value32 = PRP_FORWARDING_CH_ENCAP_VALUE(0, prp_port); 3268 PRP_FORWARDING_CREATE_ERROR_RETURN( 3269 bcm_esw_switch_encap_set( 3270 unit, encap_id_prp, &encap_info)); 3271 3272 /* setup two CustomHeader match and policy : 3273 * ==> let packet get correct orignal prp port 3274 */ 3275 for (i = 0; i < 2; i++) { 3276 int is_prp = i; 3277 int *match_id_ptr = is_prp ? &match_id_prp : &match_id_non_prp; 3278 bcm_switch_match_config_info_t match_info; 3279 bcm_switch_match_service_t match_service; 3280 uint32 match_id_hw; 3281 3282 bcm_switch_match_config_info_t_init(&match_info); 3283 match_info.value32 = PRP_FORWARDING_CH_ENCAP_VALUE(is_prp ? 0 : 1, 3284 prp_port); 3285 PRP_FORWARDING_CREATE_ERROR_RETURN( 3286 bcm_esw_switch_match_config_add( 3287 unit, bcmSwitchMatchServiceCustomHeader, 3288 &match_info, match_id_ptr)); 3289 PRP_FORWARDING_CREATE_ERROR_RETURN( 3290 bcmi_switch_match_hw_id_get( 3291 unit, *match_id_ptr, &match_service, &match_id_hw)); 3292 if (bcmSwitchMatchServiceCustomHeader != match_service) { 3293 PRP_FORWARDING_CREATE_ERROR_RETURN(BCM_E_INTERNAL); 3294 } 3295 3296 PRP_FORWARDING_CREATE_ERROR_RETURN( 3297 soc_mem_field32_modify( 3298 unit, CUSTOM_HEADER_POLICY_TABLEm, match_id_hw, 3299 PRP_PACKETf, is_prp ? 1 : 0)); 3300 3301 BCM_IF_ERROR_RETURN( 3302 _bcm_esw_src_mod_port_table_index_get(unit, my_modid, 3303 prp_port, &src_trk_idx)); 3304 BCM_IF_ERROR_RETURN( 3305 soc_mem_read(unit, SOURCE_TRUNK_MAP_TABLEm, MEM_BLOCK_ANY, 3306 src_trk_idx, mem_entry)); 3307 3308 lport_profile_idx = soc_mem_field32_get(unit, SOURCE_TRUNK_MAP_TABLEm, 3309 mem_entry, LPORT_PROFILE_IDXf); 3310 3311 PRP_FORWARDING_CREATE_ERROR_RETURN( 3312 soc_mem_field32_modify( 3313 unit, CUSTOM_HEADER_POLICY_TABLEm, match_id_hw, 3314 LPORT_PROFILE_IDXf, lport_profile_idx)); 3315 } 3316 3317 /* add IFP rule that apply on the packet from this PRP port 3318 * 1. change NET_ID source from packet (for validate the packet path ID) 3319 * 2. encap customer header 3320 * (we use id "encap_id_non_prp" 3321 * , hw will auto select "encap_id_prp" if the packet is prp-packet) 3322 * 3. redirect packet to loopback port 3323 */ 3324 PRP_FORWARDING_CREATE_ERROR_RETURN( 3325 bcm_esw_field_entry_create( 3326 unit, PRP_FORWARDING_REDIRECT_GROUP(unit), &fp_entry)); 3327 PRP_FORWARDING_CREATE_ERROR_RETURN( 3328 bcm_esw_field_qualify_InPort(unit, fp_entry, 3329 prp_port, BCM_FIELD_EXACT_MATCH_MASK)); 3330 PRP_FORWARDING_CREATE_ERROR_RETURN( 3331 bcm_esw_field_action_add(unit, fp_entry, 3332 bcmFieldActionSRNetIdSource, 3333 BCM_FIELD_SR_NET_ID_SOURCE_PACKET, 0)); 3334 PRP_FORWARDING_CREATE_ERROR_RETURN( 3335 bcm_esw_field_action_add(unit, fp_entry, 3336 bcmFieldActionSwitchEncap, 3337 encap_id_non_prp, 0)); 3338 PRP_FORWARDING_CREATE_ERROR_RETURN( 3339 bcm_esw_field_action_add(unit, fp_entry, 3340 bcmFieldActionRedirectPort, 3341 SOC_BASE_MODID(unit), 3342 PRP_FORWARDING_REDIRECT_PORT(unit))); 3343 PRP_FORWARDING_CREATE_ERROR_RETURN( 3344 bcm_esw_field_entry_install(unit, fp_entry)); 3345 3346 return BCM_E_NONE; 3347 } 3348 3349 /* SR PRP port forwarding: cleanup all prp forwaring */ 3350 STATIC void 3351 bcmi_gh2_tsn_sr_port_prp_forwarding_cleanup( 3352 int unit, 3353 int init_error) 3354 { 3355 bcm_tsn_sr_port_config_t old_config; 3356 bcm_tsn_sr_port_config_t new_config; 3357 3358 /* skip prp-init if sdk not enable this feature */ 3359 if (0 == PRP_FORWARDING_ENABLE(unit)) { 3360 return; 3361 } 3362 3363 /* set loopback port back to prp disable */ 3364 PRP_FORWARDING_CLEAN_ERROR_RETURN( 3365 bcmi_gh2_tsn_sr_port_config_get( 3366 unit, PRP_FORWARDING_REDIRECT_GPORT(unit), &old_config)); 3367 new_config = old_config; 3368 new_config.port_type = bcmTsnSrPortTypeNone; 3369 new_config.interlink_role = 1; 3370 PRP_FORWARDING_CLEAN_ERROR_RETURN( 3371 bcmi_gh2_tsn_sr_port_config_apply( 3372 unit, PRP_FORWARDING_REDIRECT_PORT(unit), 3373 &old_config, &new_config)); 3374 3375 /* destroy IFP group for prp port */ 3376 if (PRP_FORWARDING_REDIRECT_GROUP_INVALID != 3377 PRP_FORWARDING_REDIRECT_GROUP(unit)) { 3378 3379 /* if "init failed in tsn module" or 3380 * "only init tsn module" (SOC_F_ALL_MODULES_INITED flag is setup) 3381 * ==> need to clean IFP /customer header created by prp-forwarding 3382 * if during "init all" 3383 * (all module would clean resource by themselves, 3384 * and SOC_F_ALL_MODULES_INITED flag would not be setup) 3385 * ==> need not clean IFP /customer header 3386 */ 3387 if ((1 == init_error) || 3388 (SOC_CONTROL(unit)->soc_flags & SOC_F_ALL_MODULES_INITED)) { 3389 3390 /* For each PRP-port been setup before, 3391 * clean their CH encap and IFP entries 3392 */ 3393 bcm_port_t port; 3394 bcm_tsn_sr_port_config_t config; 3395 3396 PBMP_ITER(PBMP_PORT_ALL(unit), port) { 3397 bcm_gport_t gport; 3398 3399 PRP_FORWARDING_CLEAN_ERROR_RETURN( 3400 bcm_esw_port_gport_get(unit, port, &gport)); 3401 3402 PRP_FORWARDING_CLEAN_ERROR_RETURN( 3403 bcmi_gh2_tsn_sr_port_config_get(unit, gport, &config)); 3404 3405 if (1 == PRP_FORWARDING_NEED_PRP_SETTING(config)) { 3406 bcmi_gh2_tsn_sr_port_prp_forwarding_destroy(unit, port); 3407 } 3408 } 3409 3410 /* delete ifp rule for loobpack port in the group */ 3411 PRP_FORWARDING_CLEAN_ERROR_RETURN( 3412 bcmi_gh2_tsn_sr_remove_all_field_entries( 3413 unit, PRP_FORWARDING_REDIRECT_GROUP(unit), 3414 PRP_FORWARDING_REDIRECT_PORT(unit))); 3415 3416 /* destroy ifp group */ 3417 PRP_FORWARDING_CLEAN_ERROR_RETURN( 3418 bcm_esw_field_group_destroy( 3419 unit, PRP_FORWARDING_REDIRECT_GROUP(unit))); 3420 3421 } else { 3422 /* group_id should has been free by field module, do nothing */ 3423 } 3424 PRP_FORWARDING_REDIRECT_GROUP(unit) = 3425 PRP_FORWARDING_REDIRECT_GROUP_INVALID; 3426 } 3427 3428 /* destroy mutex */ 3429 if (gh2_tsn_bkinfo[unit]->gh2_prp_forwarding_bk_info.mutex != NULL) { 3430 sal_mutex_destroy( 3431 gh2_tsn_bkinfo[unit]->gh2_prp_forwarding_bk_info.mutex); 3432 gh2_tsn_bkinfo[unit]->gh2_prp_forwarding_bk_info.mutex = NULL; 3433 } 3434 } 3435 3436 /* SR PRP port forwarding: init prp forwaring feature */ 3437 STATIC int 3438 bcmi_gh2_tsn_sr_port_prp_forwarding_init( 3439 int unit) 3440 { 3441 uint32 vlan_flags; 3442 bcm_field_qset_t qset; 3443 bcm_field_entry_t fp_entry; 3444 bcm_tsn_sr_port_config_t old_config; 3445 bcm_tsn_sr_port_config_t new_config; 3446 pbmp_t pbmp; 3447 bcm_vlan_data_t *vlan_list = NULL; 3448 int vlan_cnt = 0; 3449 int port; 3450 3451 /* 3452 * INIT BOOKKEEPING 3453 */ 3454 3455 /* skip prp-init if sdk not enable this feature */ 3456 port = soc_property_get(unit, spn_SR_PRP_ENABLE, 0); 3457 PRP_FORWARDING_ENABLE(unit) = 0; 3458 if (BCM_PBMP_MEMBER(PBMP_PORT_ALL(unit), port)) { 3459 /* Check if belong to valid ports, except port 0 */ 3460 PRP_FORWARDING_ENABLE(unit) = 1; 3461 } else { 3462 /* 3463 * port = 0 : feature disabled. 3464 * other invalid port id : error configuration. 3465 */ 3466 if (port != 0) { 3467 LOG_ERROR(BSL_LS_BCM_TSN, 3468 (BSL_META_U(unit, 3469 "PRP loopback port %d is an " 3470 "invalid port.\n"), port)); 3471 return BCM_E_CONFIG; 3472 } 3473 } 3474 3475 if (0 == PRP_FORWARDING_ENABLE(unit)) { 3476 return BCM_E_NONE; 3477 } 3478 3479 /* config switch_match until 1st time to setup prp-port 3480 * (because switch module is inited after tsn module) 3481 */ 3482 PRP_FORWARDING_SWITCH_INIT(unit) = 0; 3483 3484 PRP_FORWARDING_REDIRECT_PORT(unit) = port; 3485 BCM_GPORT_LOCAL_SET(PRP_FORWARDING_REDIRECT_GPORT(unit), 3486 PRP_FORWARDING_REDIRECT_PORT(unit)); 3487 3488 PRP_FORWARDING_ERROR_RETURN( 3489 bcmi_gh2_tsn_sr_port_config_get( 3490 unit, PRP_FORWARDING_REDIRECT_GPORT(unit), &old_config)); 3491 3492 /* Create mutex */ 3493 gh2_tsn_bkinfo[unit]->gh2_prp_forwarding_bk_info.mutex = 3494 sal_mutex_create("prp_forwarding_mutex"); 3495 if (gh2_tsn_bkinfo[unit]->gh2_prp_forwarding_bk_info.mutex == NULL) { 3496 PRP_FORWARDING_ERROR_RETURN(BCM_E_MEMORY); 3497 } 3498 3499 /* 3500 * SETUP HW-RELATED SETTING 3501 * (ex. port table / ifp / customer header / l2 / vlan ) 3502 * 1. skip these if it is in warmboot 3503 * 2. prp_redirect_group of bookkeeping 3504 * would be recovered in reload() 3505 */ 3506 #if defined(BCM_WARM_BOOT_SUPPORT) 3507 if (SOC_WARM_BOOT(unit)) { 3508 return BCM_E_NONE; 3509 } 3510 #endif /* BCM_WARM_BOOT_SUPPORT */ 3511 3512 /* setup loopback port as PRP-modified */ 3513 new_config = old_config; 3514 new_config.port_type = bcmTsnSrPortTypeCount; /* for PRP-modified usage */ 3515 new_config.interlink_role = 0; 3516 new_config.net_id = 5; /* For PathID to be b'1010 (A) or b'1011 (B) */ 3517 PRP_FORWARDING_ERROR_RETURN( 3518 bcmi_gh2_tsn_sr_port_config_apply( 3519 unit, PRP_FORWARDING_REDIRECT_PORT(unit), 3520 &old_config, &new_config)); 3521 PRP_FORWARDING_ERROR_RETURN( 3522 bcm_esw_port_encap_set( 3523 unit, PRP_FORWARDING_REDIRECT_PORT(unit), BCM_PORT_ENCAP_IEEE)); 3524 PRP_FORWARDING_ERROR_RETURN( 3525 bcm_esw_port_autoneg_set( 3526 unit, PRP_FORWARDING_REDIRECT_PORT(unit), 0)); 3527 PRP_FORWARDING_ERROR_RETURN( 3528 bcm_esw_port_loopback_set( 3529 unit, PRP_FORWARDING_REDIRECT_PORT(unit), BCM_PORT_LOOPBACK_MAC)); 3530 3531 /* create a IFP group on prp-port for redirect to loopback-port 3532 * Note. we need to set this group as lowest-priority 3533 * (use BCM_FIELD_GROUP_PRIO_ANY, 3534 * it would use lowest-priority in default) 3535 * Becuase the user maybe want to setup another IFP rule on prp port 3536 * (ex. setup action DROP or PKT_NET_ID_SOURCE) 3537 */ 3538 PRP_FORWARDING_REDIRECT_GROUP(unit) = PRP_FORWARDING_REDIRECT_GROUP_INVALID; 3539 bcm_field_qset_t_init(&qset); 3540 BCM_FIELD_QSET_ADD(qset, bcmFieldQualifyInPort); 3541 PRP_FORWARDING_ERROR_RETURN( 3542 bcm_esw_field_group_create( 3543 unit, qset, BCM_FIELD_GROUP_PRIO_ANY, 3544 &PRP_FORWARDING_REDIRECT_GROUP(unit))); 3545 assert(PRP_FORWARDING_REDIRECT_GROUP(unit) != 3546 PRP_FORWARDING_REDIRECT_GROUP_INVALID); 3547 3548 /* For this loopback-port 3549 * 1. disable ingress/egress vlan check 3550 * 2. disable L2 learning 3551 * 3. disable L2 moving 3552 * 4. clear egress mask first 3553 * 5. remove this port from all VLANs 3554 * 6. change net_id source to be from ingress port. 3555 */ 3556 /* .1 */ 3557 PRP_FORWARDING_ERROR_RETURN( 3558 bcm_esw_port_vlan_member_get( 3559 unit, PRP_FORWARDING_REDIRECT_PORT(unit), &vlan_flags)); 3560 vlan_flags &= ~(BCM_PORT_VLAN_MEMBER_INGRESS); 3561 vlan_flags &= ~(BCM_PORT_VLAN_MEMBER_EGRESS); 3562 PRP_FORWARDING_ERROR_RETURN( 3563 bcm_esw_port_vlan_member_set( 3564 unit, PRP_FORWARDING_REDIRECT_PORT(unit), vlan_flags)); 3565 /* .2 */ 3566 PRP_FORWARDING_ERROR_RETURN( 3567 bcm_esw_port_control_set( 3568 unit, PRP_FORWARDING_REDIRECT_PORT(unit), 3569 bcmPortControlL2Learn, BCM_PORT_LEARN_FWD)); 3570 /* .3 */ 3571 PRP_FORWARDING_ERROR_RETURN( 3572 bcm_esw_port_control_set( 3573 unit, PRP_FORWARDING_REDIRECT_PORT(unit), 3574 bcmPortControlL2Move, BCM_PORT_LEARN_FWD)); 3575 /* .4 */ 3576 BCM_PBMP_CLEAR(pbmp); 3577 PRP_FORWARDING_ERROR_RETURN( 3578 bcm_esw_port_egress_set( 3579 unit, PRP_FORWARDING_REDIRECT_PORT(unit), 3580 SOC_BASE_MODID(unit), pbmp)); 3581 /* .5 */ 3582 BCM_PBMP_CLEAR(pbmp); 3583 BCM_PBMP_PORT_ADD(pbmp, PRP_FORWARDING_REDIRECT_PORT(unit)); 3584 PRP_FORWARDING_ERROR_RETURN( 3585 bcm_esw_vlan_list_by_pbmp( 3586 unit, pbmp, &vlan_list, &vlan_cnt)); 3587 if (vlan_cnt != 0) { 3588 int i; 3589 3590 if (NULL == vlan_list) { 3591 PRP_FORWARDING_ERROR_RETURN(BCM_E_INTERNAL); 3592 } 3593 for (i = 0; i < vlan_cnt; i++) { 3594 PRP_FORWARDING_ERROR_RETURN_WITH_CLEAN( 3595 bcm_esw_vlan_port_remove( 3596 unit, vlan_list[i].vlan_tag, pbmp), 3597 bcm_esw_vlan_list_destroy(unit, vlan_list, vlan_cnt)); 3598 } 3599 } 3600 if (NULL != vlan_list) { 3601 bcm_esw_vlan_list_destroy(unit, vlan_list, vlan_cnt); 3602 vlan_list = NULL; 3603 } 3604 /* .6 */ 3605 PRP_FORWARDING_ERROR_RETURN( 3606 bcm_esw_field_entry_create( 3607 unit, PRP_FORWARDING_REDIRECT_GROUP(unit), &fp_entry)); 3608 PRP_FORWARDING_ERROR_RETURN( 3609 bcm_esw_field_qualify_InPort( 3610 unit, fp_entry, PRP_FORWARDING_REDIRECT_PORT(unit), 3611 BCM_FIELD_EXACT_MATCH_MASK)); 3612 PRP_FORWARDING_ERROR_RETURN( 3613 bcm_esw_field_action_add( 3614 unit, fp_entry, bcmFieldActionSRNetIdSource, 3615 BCM_FIELD_SR_NET_ID_SOURCE_SRC_PORT, 0)); 3616 PRP_FORWARDING_ERROR_RETURN( 3617 bcm_esw_field_entry_install(unit, fp_entry)); 3618 3619 /* re-setup IFP/CustomerHeader 3620 * for each PRP-port (according to hw port table) 3621 */ 3622 { 3623 bcm_port_t port; 3624 bcm_tsn_sr_port_config_t config; 3625 3626 PBMP_ITER(PBMP_PORT_ALL(unit), port) { 3627 bcm_gport_t gport; 3628 3629 PRP_FORWARDING_ERROR_RETURN( 3630 bcm_esw_port_gport_get(unit, port, &gport)); 3631 3632 PRP_FORWARDING_ERROR_RETURN( 3633 bcmi_gh2_tsn_sr_port_config_get(unit, gport, &config)); 3634 3635 if (1 == PRP_FORWARDING_NEED_PRP_SETTING(config)) { 3636 PRP_FORWARDING_ERROR_RETURN( 3637 bcmi_gh2_tsn_sr_port_prp_forwarding_create(unit, port)); 3638 } 3639 } 3640 } 3641 3642 return BCM_E_NONE; 3643 } 3644 3645 #ifdef BCM_WARM_BOOT_SUPPORT 3646 /* sync prp-forwarding info to scache */ 3647 STATIC int 3648 bcmi_gh2_tsn_sr_port_prp_forwarding_sync( 3649 int unit, 3650 soc_scache_handle_t scache_handle) 3651 { 3652 uint8 *scache_ptr = NULL; 3653 int rv = BCM_E_NONE; 3654 3655 if (0 == PRP_FORWARDING_ENABLE(unit)) { 3656 return BCM_E_NONE; 3657 } 3658 3659 rv = _bcm_esw_scache_ptr_get( 3660 unit, scache_handle, TRUE, sizeof(bcm_field_group_t), 3661 &scache_ptr, BCM_TSN_WB_DEFAULT_VERSION, NULL); 3662 3663 if (BCM_SUCCESS(rv)) { 3664 if (scache_ptr == NULL) { 3665 rv = BCM_E_INTERNAL; 3666 } 3667 } 3668 3669 PRP_FORWARDING_BKINFO_LOCK(unit); 3670 if (BCM_SUCCESS(rv)) { 3671 if (PRP_FORWARDING_REDIRECT_GROUP_INVALID == 3672 PRP_FORWARDING_REDIRECT_GROUP(unit)) { 3673 rv = BCM_E_INTERNAL; 3674 } 3675 } 3676 3677 if (BCM_SUCCESS(rv)) { 3678 sal_memcpy(scache_ptr, &(PRP_FORWARDING_REDIRECT_GROUP(unit)), 3679 sizeof(bcm_field_group_t)); 3680 } 3681 PRP_FORWARDING_BKINFO_UNLOCK(unit); 3682 3683 return rv; 3684 } 3685 3686 /* recover prp-forwarding info from scache */ 3687 STATIC int 3688 bcmi_gh2_tsn_sr_port_prp_forwarding_reload( 3689 int unit, 3690 soc_scache_handle_t scache_handle) 3691 { 3692 uint8 *scache_ptr = NULL; 3693 int rv = BCM_E_NONE; 3694 3695 rv = _bcm_esw_scache_ptr_get( 3696 unit, scache_handle, FALSE, sizeof(bcm_field_group_t), 3697 &scache_ptr, BCM_TSN_WB_DEFAULT_VERSION, NULL); 3698 3699 if (BCM_E_NOT_FOUND == rv) { 3700 /* Maybe proceed with Level 1 Warm Boot */ 3701 return BCM_E_NONE; 3702 } else if (BCM_E_NONE == rv) { 3703 if (NULL == scache_ptr) { 3704 rv = BCM_E_INTERNAL; 3705 } else { 3706 sal_memcpy(&(PRP_FORWARDING_REDIRECT_GROUP(unit)), scache_ptr, 3707 sizeof(bcm_field_group_t)); 3708 } 3709 } 3710 3711 return rv; 3712 } 3713 #endif /* BCM_WARM_BOOT_SUPPORT */ 3714 3715 /* add this port into egress mask of loopback port */ 3716 STATIC int 3717 bcmi_gh2_tsn_sr_port_prp_forwarding_egress_add( 3718 int unit, 3719 bcm_port_t port) 3720 { 3721 bcm_pbmp_t pbmp; 3722 3723 BCM_PBMP_CLEAR(pbmp); 3724 BCM_IF_ERROR_RETURN( 3725 bcm_esw_port_egress_get( 3726 unit, PRP_FORWARDING_REDIRECT_PORT(unit), 3727 SOC_BASE_MODID(unit), &pbmp)); 3728 BCM_PBMP_PORT_ADD(pbmp, port); 3729 BCM_IF_ERROR_RETURN( 3730 bcm_esw_port_egress_set( 3731 unit, PRP_FORWARDING_REDIRECT_PORT(unit), 3732 SOC_BASE_MODID(unit), pbmp)); 3733 3734 return BCM_E_NONE; 3735 } 3736 3737 /* delete this port from egress mask of loopback port */ 3738 STATIC int 3739 bcmi_gh2_tsn_sr_port_prp_forwarding_egress_remove( 3740 int unit, 3741 bcm_port_t port) 3742 { 3743 bcm_pbmp_t pbmp; 3744 3745 BCM_PBMP_CLEAR(pbmp); 3746 BCM_IF_ERROR_RETURN( 3747 bcm_esw_port_egress_get( 3748 unit, PRP_FORWARDING_REDIRECT_PORT(unit), 3749 SOC_BASE_MODID(unit), &pbmp)); 3750 BCM_PBMP_PORT_REMOVE(pbmp, port); 3751 BCM_IF_ERROR_RETURN( 3752 bcm_esw_port_egress_set( 3753 unit, PRP_FORWARDING_REDIRECT_PORT(unit), 3754 SOC_BASE_MODID(unit), pbmp)); 3755 3756 return BCM_E_NONE; 3757 } 3758 3759 /* 3760 * Function: 3761 * bcmi_gh2_tsn_sr_port_config_set 3762 * Purpose: 3763 * Set SR configuration on a port 3764 * Parameters: 3765 * unit - (IN) unit number 3766 * port - (IN) port to configure 3767 * config - (IN) port SR configuration 3768 * Returns: 3769 * BCM_E_XXX 3770 * Notes: 3771 */ 3772 STATIC int 3773 bcmi_gh2_tsn_sr_port_config_set( 3774 int unit, 3775 bcm_gport_t gport, 3776 bcm_tsn_sr_port_config_t *config) 3777 { 3778 bcm_port_t port; 3779 bcm_tsn_sr_port_config_t old_config; 3780 bcm_pbmp_t netid_bmp; 3781 netid_bitmap_entry_t netid_bmp_entry; 3782 uint8 old_netid, new_netid; 3783 int rv; 3784 3785 /* Parameter check */ 3786 if (config == NULL) { 3787 return BCM_E_PARAM; 3788 } 3789 3790 /* This API implementation doesn't accept bcmTsnSrPortTypeCount */ 3791 if (config->port_type < bcmTsnSrPortTypeNone || 3792 config->port_type >= bcmTsnSrPortTypeCount) { 3793 return BCM_E_PARAM; 3794 } 3795 if (config->port_mode < bcmTsnSrPortModeDefault || 3796 config->port_mode >= bcmTsnSrPortModeCount) { 3797 return BCM_E_PARAM; 3798 } 3799 if (config->lan_id > 1) { 3800 return BCM_E_PARAM; 3801 } 3802 if (config->net_id > 7) { 3803 return BCM_E_PARAM; 3804 } 3805 3806 /* Validate and convert gport to local port */ 3807 BCM_IF_ERROR_RETURN( 3808 _bcm_esw_port_gport_validate(unit, gport, &port)); 3809 3810 /* get old previous config */ 3811 BCM_IF_ERROR_RETURN( 3812 bcmi_gh2_tsn_sr_port_config_get(unit, gport, &old_config)); 3813 3814 /* handle prp forwarding */ 3815 if (0 == PRP_FORWARDING_NEED_PRP_SETTING(old_config) && 3816 1 == PRP_FORWARDING_NEED_PRP_SETTING(*config)) { 3817 if (0 == PRP_FORWARDING_ENABLE(unit)) { 3818 return BCM_E_UNAVAIL; 3819 } 3820 PRP_FORWARDING_BKINFO_LOCK(unit); 3821 rv = bcmi_gh2_tsn_sr_port_prp_forwarding_create(unit, port); 3822 PRP_FORWARDING_BKINFO_UNLOCK(unit); 3823 BCM_IF_ERROR_RETURN(rv); 3824 } else if (1 == PRP_FORWARDING_NEED_PRP_SETTING(old_config) && 3825 0 == PRP_FORWARDING_NEED_PRP_SETTING(*config)) { 3826 if (0 == PRP_FORWARDING_ENABLE(unit)) { 3827 return BCM_E_UNAVAIL; 3828 } 3829 PRP_FORWARDING_BKINFO_LOCK(unit); 3830 bcmi_gh2_tsn_sr_port_prp_forwarding_destroy(unit, port); 3831 PRP_FORWARDING_BKINFO_UNLOCK(unit); 3832 } 3833 3834 /* need handle egress mask on loopback port if PRP enable */ 3835 if (1 == PRP_FORWARDING_ENABLE(unit)) { 3836 if (0 == PRP_FORWARDING_NEED_EGRESS_MASK_SETTING(old_config) && 3837 1 == PRP_FORWARDING_NEED_EGRESS_MASK_SETTING(*config)) { 3838 BCM_IF_ERROR_RETURN( 3839 bcmi_gh2_tsn_sr_port_prp_forwarding_egress_add(unit, port)); 3840 } else if (1 == PRP_FORWARDING_NEED_EGRESS_MASK_SETTING(old_config) && 3841 0 == PRP_FORWARDING_NEED_EGRESS_MASK_SETTING(*config)) { 3842 BCM_IF_ERROR_RETURN( 3843 bcmi_gh2_tsn_sr_port_prp_forwarding_egress_remove(unit, port)); 3844 } 3845 } 3846 3847 /* Configure NET_ID bitmap for NET_ID filtering on mutlicast packets */ 3848 old_netid = 0; 3849 new_netid = 0; 3850 if (old_config.port_type == bcmTsnSrPortTypePrp || 3851 old_config.port_mode == bcmTsnSrPortModeInterworkingPrp) { 3852 old_netid = old_config.net_id; 3853 } 3854 if (config->port_type == bcmTsnSrPortTypePrp || 3855 config->port_mode == bcmTsnSrPortModeInterworkingPrp) { 3856 new_netid = config->net_id; 3857 } 3858 if (old_netid != new_netid) { 3859 sal_memset(&netid_bmp_entry, 0, sizeof(netid_bmp_entry)); 3860 if (old_netid) { 3861 /* Remove this port from old NET_ID bitmap if applicable */ 3862 BCM_IF_ERROR_RETURN( 3863 soc_mem_read(unit, NETID_BITMAPm, MEM_BLOCK_ANY, 3864 old_netid, &netid_bmp_entry)); 3865 soc_mem_pbmp_field_get( 3866 unit, NETID_BITMAPm, &netid_bmp_entry, BITMAPf, &netid_bmp); 3867 BCM_PBMP_PORT_REMOVE(netid_bmp, port); 3868 soc_mem_pbmp_field_set( 3869 unit, NETID_BITMAPm, &netid_bmp_entry, BITMAPf, &netid_bmp); 3870 BCM_IF_ERROR_RETURN( 3871 soc_mem_write(unit, NETID_BITMAPm, MEM_BLOCK_ALL, 3872 old_netid, &netid_bmp_entry)); 3873 } 3874 if (new_netid) { 3875 /* Add this port to new NET_ID bitmap if applicable */ 3876 BCM_IF_ERROR_RETURN( 3877 soc_mem_read(unit, NETID_BITMAPm, MEM_BLOCK_ANY, 3878 new_netid, &netid_bmp_entry)); 3879 soc_mem_pbmp_field_get( 3880 unit, NETID_BITMAPm, &netid_bmp_entry, BITMAPf, &netid_bmp); 3881 BCM_PBMP_PORT_ADD(netid_bmp, port); 3882 soc_mem_pbmp_field_set( 3883 unit, NETID_BITMAPm, &netid_bmp_entry, BITMAPf, &netid_bmp); 3884 BCM_IF_ERROR_RETURN( 3885 soc_mem_write(unit, NETID_BITMAPm, MEM_BLOCK_ALL, 3886 new_netid, &netid_bmp_entry)); 3887 } 3888 } 3889 3890 /* Call the shared configuration apply to configure */ 3891 BCM_IF_ERROR_RETURN( 3892 bcmi_gh2_tsn_sr_port_config_apply(unit, port, &old_config, config)); 3893 return BCM_E_NONE; 3894 } 3895 #endif /* BCM_TSN_SR_SUPPORT */ 3896 3897 /* TSN flow mgmt - get number of flows */ 3898 STATIC int 3899 bcmi_gh2_tsn_flows_get_num_flows(int unit, int *max_flows) 3900 { 3901 /* parameter check */ 3902 if (!SOC_UNIT_VALID(unit) || NULL == max_flows) { 3903 return BCM_E_PARAM; 3904 } 3905 3906 *max_flows = TSN_FLOWS_MAX_NUM_OF_FLOWS; 3907 3908 return BCM_E_NONE; 3909 } 3910 3911 /* TSN flow mgmt - convert flow index to HW flow ID */ 3912 STATIC int 3913 bcmi_gh2_tsn_flows_get_hw_flow_id(int unit, int fidx, uint32 *hw_id) 3914 { 3915 /* parameter check */ 3916 if (!SOC_UNIT_VALID(unit) || NULL == hw_id || fidx < 0 || 3917 fidx >= TSN_FLOWS_MAX_NUM_OF_FLOWS) { 3918 return BCM_E_PARAM; 3919 } 3920 3921 /* Convert it */ 3922 *hw_id = (uint32)TSN_FLOWS_IDX_TO_HW_ID(fidx); 3923 return BCM_E_NONE; 3924 } 3925 3926 /* TSN flow mgmt - convert flow index to HW flow ID */ 3927 STATIC int 3928 bcmi_gh2_tsn_flows_get_sw_flow_idx(int unit, uint32 hw_id, int *fidx) 3929 { 3930 int idx; 3931 3932 /* parameter check */ 3933 if (!SOC_UNIT_VALID(unit) || NULL == fidx) { 3934 return BCM_E_PARAM; 3935 } 3936 3937 /* Convert it */ 3938 idx = TSN_FLOWS_HW_ID_TO_IDX((int)hw_id); 3939 3940 /* Check if it's valid */ 3941 if (idx < 0 || idx >= TSN_FLOWS_MAX_NUM_OF_FLOWS) { 3942 return BCM_E_PARAM; 3943 } 3944 3945 *fidx = idx; 3946 return BCM_E_NONE; 3947 } 3948 3949 /* TSN flow mgmt - check flow config */ 3950 STATIC int 3951 bcmi_gh2_tsn_flows_check_flow_config(int unit, bcm_tsn_flow_config_t *cfg) 3952 { 3953 int index; 3954 bcm_tsn_mtu_profile_type_t type; 3955 3956 /* parameter check */ 3957 TSN_BKINFO_IS_INIT(unit); 3958 if (NULL == cfg) { 3959 return BCM_E_PARAM; 3960 } 3961 3962 /* Check MTU profile id */ 3963 if (soc_feature(unit, soc_feature_tsn_mtu_stu)) { 3964 /* Using MTU decode function to do profile id validation */ 3965 BCM_IF_ERROR_RETURN(bcmi_gh2_tsn_mtu_profile_decode( 3966 unit, cfg->ingress_mtu_profile, &type, &index)); 3967 if (type == bcmTsnMtuProfileTypeEgress) { 3968 return BCM_E_PARAM; 3969 } 3970 } 3971 3972 return BCM_E_NONE; 3973 } 3974 3975 /* TSN flow mgmt - write flow config */ 3976 STATIC int 3977 bcmi_gh2_tsn_flows_write_flow( 3978 int unit, 3979 int idx, 3980 bcm_tsn_flow_config_t *config) 3981 { 3982 soc_mem_t mem; 3983 uint32 v = 0; 3984 cut_through_attribute_entry_t ct_entry; 3985 ing_mtu_check_1_entry_t mtu_ent; 3986 uint32 hw_id; 3987 int mtu_hw_index; 3988 bcm_tsn_mtu_profile_type_t type; 3989 int rv; 3990 3991 /* parameter check */ 3992 TSN_BKINFO_IS_INIT(unit); 3993 if (NULL == config || idx < 0 || idx >= TSN_FLOWS_MAX_NUM_OF_FLOWS) { 3994 return BCM_E_PARAM; 3995 } 3996 3997 /* 3998 * Per flow disable cut-through 3999 * Write to HW with HW index idx+1 since entry 0 is not visible to SW 4000 */ 4001 if (soc_feature(unit, soc_feature_tsn_flow_no_asf_select)) { 4002 mem = CUT_THROUGH_ATTRIBUTEm; 4003 sal_memset(&ct_entry, 0, sizeof(ct_entry)); 4004 v = (config->flags & BCM_TSN_FLOW_CONFIG_DO_NOT_CUT_THROUGH) ? 1 : 0; 4005 soc_mem_field32_set(unit, mem, &ct_entry, DO_NOT_CUT_THROUGHf, v); 4006 rv = soc_mem_write(unit, mem, MEM_BLOCK_ALL, 4007 TSN_FLOWS_IDX_TO_HW_ID(idx), 4008 &ct_entry); 4009 if (SOC_FAILURE(rv)) { 4010 LOG_ERROR(BSL_LS_BCM_TSN, 4011 (BSL_META_U(unit, "Failed to write mem[%s]"), 4012 SOC_MEM_NAME(unit, mem))); 4013 return rv; 4014 } 4015 } else { 4016 if (config->flags & BCM_TSN_FLOW_CONFIG_DO_NOT_CUT_THROUGH) { 4017 LOG_VERBOSE(BSL_LS_BCM_TSN, 4018 (BSL_META_U(unit, 4019 "TSN flow disable cut-through " 4020 "is not configurable\n"))); 4021 return BCM_E_PARAM; 4022 } 4023 } 4024 /* MTU profile id HW writing */ 4025 if (soc_feature(unit, soc_feature_tsn_mtu_stu)) { 4026 hw_id = (uint32)TSN_FLOWS_IDX_TO_HW_ID(idx); 4027 mem = ING_MTU_CHECK_1m; 4028 MEM_LOCK(unit, mem); 4029 sal_memset(&mtu_ent, 0, sizeof(mtu_ent)); 4030 rv = soc_mem_read(unit, mem, MEM_BLOCK_ANY, hw_id, &mtu_ent); 4031 if (SOC_FAILURE(rv)) { 4032 LOG_ERROR(BSL_LS_BCM_TSN, 4033 (BSL_META_U(unit, "Failed to read mem[%s]"), 4034 SOC_MEM_NAME(unit, mem))); 4035 MEM_UNLOCK(unit, mem); 4036 return rv; 4037 } 4038 type = bcmTsnMtuProfileTypeIngress; 4039 BCM_IF_ERROR_RETURN(bcmi_gh2_tsn_mtu_profile_decode( 4040 unit, config->ingress_mtu_profile, 4041 &type, &mtu_hw_index)); 4042 soc_mem_field32_set(unit, mem, &mtu_ent, MTU_PROFILE_INDEXf, 4043 mtu_hw_index); 4044 4045 rv = soc_mem_write(unit, mem, MEM_BLOCK_ALL, hw_id, &mtu_ent); 4046 if (SOC_FAILURE(rv)) { 4047 LOG_ERROR(BSL_LS_BCM_TSN, 4048 (BSL_META_U(unit, "Failed to write mem[%s]"), 4049 SOC_MEM_NAME(unit, mem))); 4050 MEM_UNLOCK(unit, mem); 4051 return rv; 4052 } 4053 MEM_UNLOCK(unit, mem); 4054 } 4055 4056 return BCM_E_NONE; 4057 } 4058 4059 #ifdef BCM_WARM_BOOT_SUPPORT 4060 /* TSN flow mgmt - read flow config (for warm boot) */ 4061 STATIC int 4062 bcmi_gh2_tsn_flows_read_flow( 4063 int unit, 4064 int idx, 4065 bcm_tsn_flow_config_t *config) 4066 { 4067 soc_mem_t mem; 4068 cut_through_attribute_entry_t ct_entry; 4069 int rv = BCM_E_NONE; 4070 ing_mtu_check_1_entry_t mtu_ent; 4071 uint32 hw_id; 4072 int mtu_idx, mtu_id; 4073 4074 /* parameter check */ 4075 TSN_BKINFO_IS_INIT(unit); 4076 if (!soc_feature(unit, soc_feature_tsn)) { 4077 return (BCM_E_UNAVAIL); 4078 } 4079 if (NULL == config || idx < 0 || idx >= TSN_FLOWS_MAX_NUM_OF_FLOWS) { 4080 return BCM_E_PARAM; 4081 } 4082 4083 /* This routine is for warm boot only */ 4084 if (!SOC_WARM_BOOT(unit)) { 4085 return BCM_E_UNAVAIL; 4086 } 4087 4088 /* Get config from hardware */ 4089 mem = CUT_THROUGH_ATTRIBUTEm; 4090 sal_memset(&ct_entry, 0, sizeof(ct_entry)); 4091 rv = soc_mem_read(unit, mem, MEM_BLOCK_ANY, 4092 TSN_FLOWS_IDX_TO_HW_ID(idx), &ct_entry); 4093 if (SOC_FAILURE(rv)) { 4094 LOG_ERROR(BSL_LS_BCM_TSN, 4095 (BSL_META_U(unit, "Failed to read mem[%s]"), 4096 SOC_MEM_NAME(unit, mem))); 4097 return rv; 4098 } 4099 if (soc_mem_field32_get(unit, mem, &ct_entry, DO_NOT_CUT_THROUGHf)) { 4100 config->flags |= BCM_TSN_FLOW_CONFIG_DO_NOT_CUT_THROUGH; 4101 } 4102 4103 /* MTU TSN flow warm boot read */ 4104 if (soc_feature(unit, soc_feature_tsn_mtu_stu)) { 4105 mem = ING_MTU_CHECK_1m; 4106 hw_id = (uint32)TSN_FLOWS_IDX_TO_HW_ID(idx); 4107 sal_memset(&mtu_ent, 0, sizeof(mtu_ent)); 4108 rv = soc_mem_read(unit, mem, MEM_BLOCK_ANY, hw_id, &mtu_ent); 4109 if (SOC_FAILURE(rv)) { 4110 LOG_ERROR(BSL_LS_BCM_TSN, 4111 (BSL_META_U(unit, "Failed to read mem[%s]"), 4112 SOC_MEM_NAME(unit, mem))); 4113 return rv; 4114 } 4115 mtu_idx = soc_mem_field32_get(unit, mem, &mtu_ent, MTU_PROFILE_INDEXf); 4116 rv = bcmi_gh2_tsn_mtu_profile_encode(unit, mtu_idx, 4117 bcmTsnMtuProfileTypeIngress, 4118 &mtu_id); 4119 if (SOC_FAILURE(rv)) { 4120 LOG_ERROR(BSL_LS_BCM_TSN, 4121 (BSL_META_U(unit, "Failed to encode mtu profile" 4122 " from idx = %d"), mtu_idx)); 4123 return rv; 4124 } 4125 config->ingress_mtu_profile = mtu_id; 4126 } 4127 return BCM_E_NONE; 4128 } 4129 #endif /* BCM_WARM_BOOT_SUPPORT */ 4130 4131 /* TSN flow mgmt - clear flow config */ 4132 STATIC int 4133 bcmi_gh2_tsn_flows_clear_flow_mtu(int unit, int idx) 4134 { 4135 soc_mem_t mem; 4136 ing_mtu_check_1_entry_t mtu_ent; 4137 int rv; 4138 uint32 hw_id; 4139 4140 TSN_BKINFO_IS_INIT(unit); 4141 if (!soc_feature(unit, soc_feature_tsn_mtu_stu)) { 4142 return BCM_E_UNAVAIL; 4143 } 4144 4145 hw_id = (uint32)TSN_FLOWS_IDX_TO_HW_ID(idx); 4146 mem = ING_MTU_CHECK_1m; 4147 MEM_LOCK(unit, mem); 4148 sal_memset(&mtu_ent, 0, sizeof(mtu_ent)); 4149 rv = soc_mem_read(unit, mem, MEM_BLOCK_ANY, hw_id, &mtu_ent); 4150 if (SOC_FAILURE(rv)) { 4151 LOG_ERROR(BSL_LS_BCM_TSN, 4152 (BSL_META_U(unit, "Failed to read mem[%s]"), 4153 SOC_MEM_NAME(unit, mem))); 4154 MEM_UNLOCK(unit, mem); 4155 return rv; 4156 } 4157 soc_mem_field32_set(unit, mem, &mtu_ent, MTU_PROFILE_INDEXf, 0); 4158 4159 rv = soc_mem_write(unit, mem, MEM_BLOCK_ALL, hw_id, &mtu_ent); 4160 if (SOC_FAILURE(rv)) { 4161 LOG_ERROR(BSL_LS_BCM_TSN, 4162 (BSL_META_U(unit, "Failed to write mem[%s]"), 4163 SOC_MEM_NAME(unit, mem))); 4164 MEM_UNLOCK(unit, mem); 4165 return rv; 4166 } 4167 MEM_UNLOCK(unit, mem); 4168 4169 return BCM_E_NONE; 4170 } 4171 4172 4173 /* TSN flow mgmt - clear flow config */ 4174 STATIC int 4175 bcmi_gh2_tsn_flows_clear_flow(int unit, int idx) 4176 { 4177 /* parameter check */ 4178 if (!SOC_UNIT_VALID(unit) || 4179 idx < 0 || idx >= TSN_FLOWS_MAX_NUM_OF_FLOWS) { 4180 return BCM_E_PARAM; 4181 } 4182 4183 /* Clear MTU profile id HW */ 4184 if (soc_feature(unit, soc_feature_tsn_mtu_stu)) { 4185 return bcmi_gh2_tsn_flows_clear_flow_mtu(unit, idx); 4186 } 4187 4188 return BCM_E_NONE; 4189 } 4190 4191 /* 4192 * TSN/SR table size is 8 * 16, sw_idx = 0 ~ 7 4193 * each sw_idx represent a group of 16 new priority entries 4194 */ 4195 #define GH2_PRI_MAP_TSN_SHIFT (4) 4196 #define GH2_PRI_MAP_TSN_MASK (0xF) 4197 #define GH2_PRI_MAP_TSN_TAB_SIZE (8) 4198 #define GH2_PRI_MAP_TSN_ENT_SIZE (16) 4199 #if defined(BCM_TSN_SR_SUPPORT) 4200 #define GH2_PRI_MAP_SR_SHIFT (4) 4201 #define GH2_PRI_MAP_SR_MASK (0xF) 4202 #define GH2_PRI_MAP_SR_TAB_SIZE (8) 4203 #define GH2_PRI_MAP_SR_ENT_SIZE (16) 4204 #endif /* BCM_TSN_SR_SUPPORT */ 4205 4206 /* 4207 * Egress STU/MTU table is 128x8, and the 128 is the max port count. 4208 * However, it could be smaller in fact. The max actual number of ports is 4209 * more reasonable. 4210 * refer to GH2 EGR_MTU_CHECK/EGR_STU_CHECK (66 ports) 4211 */ 4212 #define GH2_PRI_MAP_MTU_SHIFT (3) 4213 #define GH2_PRI_MAP_MTU_MASK (0x7) 4214 #define GH2_PRI_MAP_MTU_TAB_SIZE (66) 4215 #define GH2_PRI_MAP_MTU_ENT_SIZE (8) 4216 #define GH2_PRI_MAP_STU_SHIFT (3) 4217 #define GH2_PRI_MAP_STU_MASK (0x7) 4218 #define GH2_PRI_MAP_STU_TAB_SIZE (66) 4219 #define GH2_PRI_MAP_STU_ENT_SIZE (8) 4220 4221 /* OFFSET is only 3 bits and INT_PRI is only 4 bits */ 4222 #define GH2_PRI_MAP_TSN_MAX_FLOW_VALUE (8) 4223 #define GH2_PRI_MAP_SR_MAX_FLOW_VALUE (8) 4224 #define GH2_PRI_MAP_TSN_MAX_NEW_PRI_VALUE (16) 4225 #define GH2_PRI_MAP_SR_MAX_NEW_PRI_VALUE (16) 4226 /* 4227 * The default setting is placed in the 1st profile (sw_idx = 0) 4228 * of TSN/SR flow initially 4229 * Note: 4230 * 2rd to Nth profiles with values default_offset and default_new_pri 4231 * are recognized as empty setting. 4232 */ 4233 STATIC const uint32 default_offset[GH2_PRI_MAP_TSN_ENT_SIZE] = 4234 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 4235 STATIC const uint32 default_new_pri[GH2_PRI_MAP_TSN_ENT_SIZE] = 4236 {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; 4237 4238 /* 4239 * Function: 4240 * bcmi_gh2_tsn_pri_map_tsn_set 4241 * Purpose: 4242 * Set the Priority Map configuration to hardware 4243 * Parameters: 4244 * unit - (IN) Unit number 4245 * sw_idx - (IN) SW memory index 4246 * config - (OUT) Priority Map configuration 4247 * Returns: 4248 * BCM_E_xxx 4249 */ 4250 STATIC int 4251 bcmi_gh2_tsn_pri_map_tsn_set( 4252 int unit, 4253 uint32 sw_idx, 4254 bcm_tsn_pri_map_config_t *config) 4255 { 4256 uint32 hw_idx; 4257 uint32 entry_idx; 4258 soc_mem_t mem = TSN_PRI_OFFSETm; 4259 tsn_pri_offset_entry_t data; 4260 uint32 field_data; 4261 int is_default_offset = TRUE, is_default_new_pri = TRUE; 4262 bcm_tsn_pri_map_entry_t *map_entry; 4263 4264 if (!soc_feature(unit, soc_feature_tsn)) { 4265 return BCM_E_UNAVAIL; 4266 } 4267 4268 if (!(sw_idx < GH2_PRI_MAP_TSN_TAB_SIZE)) { 4269 LOG_ERROR(BSL_LS_BCM_TSN, 4270 (BSL_META_U(unit, 4271 "Invalid sw_idx(%d).\n"), 4272 sw_idx)); 4273 assert(sw_idx < GH2_PRI_MAP_TSN_TAB_SIZE); 4274 return BCM_E_PARAM; 4275 } 4276 4277 /* Parameter validation */ 4278 if (NULL == config) { 4279 return BCM_E_PARAM; 4280 } 4281 4282 /* Set the flow_offset and new_int_pri to TSN_PRI_OFFSETm */ 4283 entry_idx = 0; 4284 for (hw_idx = (sw_idx << GH2_PRI_MAP_TSN_SHIFT); 4285 hw_idx < (sw_idx << GH2_PRI_MAP_TSN_SHIFT) + GH2_PRI_MAP_TSN_ENT_SIZE; 4286 hw_idx++) { 4287 4288 map_entry = &(config->map_entries[entry_idx]); 4289 is_default_offset = 4290 (BCM_TSN_PRI_MAP_ENTRY_FLOW_OFFSET & (map_entry->flags)) ? 4291 FALSE : TRUE; 4292 is_default_new_pri = 4293 (BCM_TSN_PRI_MAP_ENTRY_NEW_INT_PRI & (map_entry->flags)) ? 4294 FALSE : TRUE; 4295 4296 BCM_IF_ERROR_RETURN( 4297 soc_mem_read(unit, mem, MEM_BLOCK_ANY, hw_idx, &data)); 4298 4299 if (SOC_MEM_FIELD_VALID(unit, mem, OFFSETf)) { 4300 if (TRUE == is_default_offset) { 4301 field_data = default_offset[entry_idx]; 4302 } 4303 else { 4304 field_data = map_entry->flow_offset; 4305 } 4306 4307 /* Check if the value fit the target field range */ 4308 BCM_IF_ERROR_RETURN 4309 (soc_mem_field32_fit( 4310 unit, mem, OFFSETf, 4311 field_data)); 4312 soc_TSN_PRI_OFFSETm_field_set(unit, &data, OFFSETf, &field_data); 4313 } 4314 else { 4315 return BCM_E_INTERNAL; 4316 } 4317 4318 if (SOC_MEM_FIELD_VALID(unit, mem, INT_PRIf)) { 4319 if (TRUE == is_default_new_pri) { 4320 field_data = default_new_pri[entry_idx]; 4321 } 4322 else { 4323 field_data = map_entry->new_int_pri; 4324 } 4325 4326 /* Check if the value fit the target field range */ 4327 BCM_IF_ERROR_RETURN 4328 (soc_mem_field32_fit( 4329 unit, mem, INT_PRIf, 4330 field_data)); 4331 soc_TSN_PRI_OFFSETm_field_set(unit, &data, INT_PRIf, &field_data); 4332 } 4333 else { 4334 return BCM_E_INTERNAL; 4335 } 4336 BCM_IF_ERROR_RETURN( 4337 soc_mem_write(unit, mem, MEM_BLOCK_ALL, hw_idx, &data)); 4338 entry_idx++; 4339 } 4340 4341 return BCM_E_NONE; 4342 } 4343 4344 /* 4345 * Function: 4346 * bcmi_gh2_tsn_pri_map_tsn_get 4347 * Purpose: 4348 * Get the Priority Map configuration from hardware 4349 * Parameters: 4350 * unit - (IN) Unit number 4351 * sw_idx - (IN) SW memory index 4352 * config - (OUT) Priority Map configuration 4353 * Returns: 4354 * BCM_E_xxx 4355 */ 4356 STATIC int 4357 bcmi_gh2_tsn_pri_map_tsn_get( 4358 int unit, 4359 uint32 sw_idx, 4360 bcm_tsn_pri_map_config_t *config) 4361 { 4362 uint32 hw_idx; 4363 uint32 entry_idx; 4364 soc_mem_t mem = TSN_PRI_OFFSETm; 4365 tsn_pri_offset_entry_t data; 4366 uint32 field_data; 4367 int is_default_offset = TRUE, is_default_new_pri = TRUE; 4368 4369 if (!soc_feature(unit, soc_feature_tsn)) { 4370 return BCM_E_UNAVAIL; 4371 } 4372 4373 if (!(sw_idx < GH2_PRI_MAP_TSN_TAB_SIZE)) { 4374 LOG_ERROR(BSL_LS_BCM_TSN, 4375 (BSL_META_U(unit, 4376 "Invalid sw_idx(%d).\n"), 4377 sw_idx)); 4378 assert(sw_idx < GH2_PRI_MAP_TSN_TAB_SIZE); 4379 return BCM_E_PARAM; 4380 } 4381 4382 /* Parameter validation */ 4383 if (NULL == config) { 4384 return BCM_E_PARAM; 4385 } 4386 4387 /* Get the flow_offset and new_int_pri from TSN_PRI_OFFSETm */ 4388 entry_idx = 0; 4389 for (hw_idx = (sw_idx << GH2_PRI_MAP_TSN_SHIFT); 4390 hw_idx < (sw_idx << GH2_PRI_MAP_TSN_SHIFT) + GH2_PRI_MAP_TSN_ENT_SIZE; 4391 hw_idx++) { 4392 4393 BCM_IF_ERROR_RETURN( 4394 soc_mem_read(unit, mem, MEM_BLOCK_ANY, hw_idx, &data)); 4395 4396 if (SOC_MEM_FIELD_VALID(unit, mem, OFFSETf)) { 4397 soc_TSN_PRI_OFFSETm_field_get(unit, &data, OFFSETf, &field_data); 4398 config->map_entries[entry_idx].flow_offset = field_data; 4399 4400 /* check if the current setting from HW is default setting */ 4401 if (default_offset[entry_idx] != field_data) { 4402 is_default_offset = FALSE; 4403 } 4404 } 4405 else { 4406 return BCM_E_INTERNAL; 4407 } 4408 4409 if (SOC_MEM_FIELD_VALID(unit, mem, INT_PRIf)) { 4410 soc_TSN_PRI_OFFSETm_field_get(unit, &data, INT_PRIf, &field_data); 4411 config->map_entries[entry_idx].new_int_pri = field_data; 4412 4413 /* check if the current setting from HW is default setting */ 4414 if (default_new_pri[entry_idx] != field_data) { 4415 is_default_new_pri = FALSE; 4416 } 4417 } 4418 else { 4419 return BCM_E_INTERNAL; 4420 } 4421 entry_idx++; 4422 } 4423 4424 /* Set TSN related setting */ 4425 config->map_type = bcmTsnPriMapTypeTsnFlow; 4426 config->num_map_entries = GH2_PRI_MAP_TSN_ENT_SIZE; 4427 4428 /* Check if the HW setting is default setting, and set valid flags. */ 4429 for (entry_idx = 0; 4430 entry_idx < GH2_PRI_MAP_TSN_ENT_SIZE; 4431 entry_idx++) { 4432 config->map_entries[entry_idx].flags = 0; 4433 4434 if (FALSE == is_default_offset) { 4435 config->map_entries[entry_idx].flags |= 4436 BCM_TSN_PRI_MAP_ENTRY_FLOW_OFFSET; 4437 } 4438 if (FALSE == is_default_new_pri) { 4439 config->map_entries[entry_idx].flags |= 4440 BCM_TSN_PRI_MAP_ENTRY_NEW_INT_PRI; 4441 } 4442 } 4443 return BCM_E_NONE; 4444 } 4445 4446 /* 4447 * Function: 4448 * bcmi_gh2_tsn_pri_map_tsn_delete 4449 * Purpose: 4450 * Delete the Priority Map configuration on hardware 4451 * Parameters: 4452 * unit - (IN) Unit number 4453 * sw_idx - (IN) SW memory index 4454 * Returns: 4455 * BCM_E_xxx 4456 */ 4457 STATIC int 4458 bcmi_gh2_tsn_pri_map_tsn_delete( 4459 int unit, 4460 uint32 sw_idx) 4461 { 4462 uint32 hw_idx; 4463 uint32 entry_idx; 4464 soc_mem_t mem = TSN_PRI_OFFSETm; 4465 tsn_pri_offset_entry_t data; 4466 uint32 field_data; 4467 4468 LOG_VERBOSE(BSL_LS_BCM_TSN, 4469 (BSL_META_U(unit, 4470 "bcmi_gh2_tsn_pri_map_tsn_delete:" 4471 "sw_idx %d\n"), 4472 sw_idx)); 4473 4474 if (!soc_feature(unit, soc_feature_tsn)) { 4475 return BCM_E_UNAVAIL; 4476 } 4477 4478 /* 1st profile should exist all the time, cannot delete sw_idx 0 */ 4479 if (!((sw_idx > 0) && (sw_idx < GH2_PRI_MAP_TSN_TAB_SIZE))) { 4480 LOG_ERROR(BSL_LS_BCM_TSN, 4481 (BSL_META_U(unit, 4482 "Invalid sw_idx(%d).\n"), 4483 sw_idx)); 4484 assert((sw_idx > 0) && (sw_idx < GH2_PRI_MAP_TSN_TAB_SIZE)); 4485 return BCM_E_PARAM; 4486 } 4487 4488 if (sw_idx == 0) { 4489 LOG_WARN(BSL_LS_BCM_TSN, 4490 (BSL_META_U(unit, 4491 "cannot delete default profile(sw_idx = 0).\n"))); 4492 return BCM_E_NONE; 4493 } 4494 4495 /* Set the flow_offset and new_int_pri to TSN_PRI_OFFSETm */ 4496 entry_idx = 0; 4497 for (hw_idx = (sw_idx << GH2_PRI_MAP_TSN_SHIFT); 4498 hw_idx < (sw_idx << GH2_PRI_MAP_TSN_SHIFT) + GH2_PRI_MAP_TSN_ENT_SIZE; 4499 hw_idx++) { 4500 4501 BCM_IF_ERROR_RETURN( 4502 soc_mem_read(unit, mem, MEM_BLOCK_ANY, hw_idx, &data)); 4503 4504 if (SOC_MEM_FIELD_VALID(unit, mem, OFFSETf)) { 4505 field_data = default_offset[entry_idx]; 4506 soc_TSN_PRI_OFFSETm_field_set(unit, &data, OFFSETf, &field_data); 4507 } 4508 else { 4509 return BCM_E_INTERNAL; 4510 } 4511 4512 if (SOC_MEM_FIELD_VALID(unit, mem, INT_PRIf)) { 4513 field_data = default_new_pri[entry_idx]; 4514 soc_TSN_PRI_OFFSETm_field_set(unit, &data, INT_PRIf, &field_data); 4515 } 4516 else { 4517 return BCM_E_INTERNAL; 4518 } 4519 BCM_IF_ERROR_RETURN( 4520 soc_mem_write(unit, mem, MEM_BLOCK_ALL, hw_idx, &data)); 4521 entry_idx++; 4522 } 4523 return BCM_E_NONE; 4524 } 4525 4526 /* 4527 * Function: 4528 * bcmi_gh2_tsn_pri_map_tsn_hw_index_get 4529 * Purpose: 4530 * Get HW memory base index 4531 * Parameters: 4532 * unit - (IN) Unit number 4533 * sw_idx - (IN) SW memory index 4534 * hw_index - (OUT) HW memory base index 4535 * Returns: 4536 * BCM_E_xxx 4537 */ 4538 STATIC int 4539 bcmi_gh2_tsn_pri_map_tsn_hw_index_get( 4540 int unit, 4541 uint32 sw_idx, 4542 uint32 *hw_index) 4543 { 4544 if (!soc_feature(unit, soc_feature_tsn)) { 4545 return BCM_E_UNAVAIL; 4546 } 4547 4548 /* Parameter validation */ 4549 if (NULL == hw_index || 4550 GH2_PRI_MAP_TSN_TAB_SIZE <= sw_idx) { 4551 return BCM_E_PARAM; 4552 } 4553 *hw_index = sw_idx; 4554 4555 LOG_VERBOSE(BSL_LS_BCM_TSN, 4556 (BSL_META_U(unit, 4557 "bcmi_gh2_tsn_pri_map_tsn_hw_index_get:" 4558 "sw_idx %d, hw_index %d\n"), 4559 sw_idx, *hw_index)); 4560 return BCM_E_NONE; 4561 } 4562 4563 /* 4564 * Function: 4565 * bcmi_gh2_tsn_pri_map_tsn_sw_idx_get 4566 * Purpose: 4567 * Get SW memory index 4568 * Parameters: 4569 * unit - (IN) Unit number 4570 * hw_index - (IN) HW memory base index 4571 * sw_idx - (OUT) SW memory index 4572 * Returns: 4573 * BCM_E_xxx 4574 */ 4575 STATIC int 4576 bcmi_gh2_tsn_pri_map_tsn_sw_idx_get( 4577 int unit, 4578 uint32 hw_index, 4579 uint32 *sw_idx) 4580 { 4581 if (!soc_feature(unit, soc_feature_tsn)) { 4582 return BCM_E_UNAVAIL; 4583 } 4584 4585 /* Parameter validation */ 4586 if (NULL == sw_idx || 4587 GH2_PRI_MAP_TSN_TAB_SIZE * GH2_PRI_MAP_TSN_ENT_SIZE <= hw_index) { 4588 return BCM_E_PARAM; 4589 } 4590 *sw_idx = hw_index; 4591 4592 LOG_VERBOSE(BSL_LS_BCM_TSN, 4593 (BSL_META_U(unit, 4594 "bcmi_gh2_tsn_pri_map_tsn_sw_idx_get:" 4595 "hw_index %d, sw_idx %d\n"), 4596 hw_index, *sw_idx)); 4597 return BCM_E_NONE; 4598 } 4599 4600 /* 4601 * Function: 4602 * bcmi_gh2_tsn_pri_map_tsn_wb_hw_existed 4603 * Purpose: 4604 * check if the HW existed value or not 4605 * Parameters: 4606 * unit - (IN) Unit being initialized 4607 * sw_idx - (IN) SW memory index 4608 * Returns: 4609 * BCM_E_NOT_FOUND means HW doesn't exist 4610 * BCM_E_NONE means HW existed 4611 */ 4612 STATIC int 4613 bcmi_gh2_tsn_pri_map_tsn_wb_hw_existed( 4614 int unit, 4615 uint32 sw_idx) 4616 { 4617 #if defined(BCM_WARM_BOOT_SUPPORT) 4618 uint32 hw_idx; 4619 uint32 entry_idx; 4620 uint32 field_data; 4621 soc_mem_t mem = TSN_PRI_OFFSETm; 4622 tsn_pri_offset_entry_t data; 4623 int is_default_offset = TRUE, is_default_new_pri = TRUE; 4624 4625 LOG_VERBOSE(BSL_LS_BCM_TSN, 4626 (BSL_META_U(unit, 4627 "bcmi_gh2_tsn_pri_map_tsn_wb_hw_existed:" 4628 "sw_idx %d\n"), 4629 sw_idx)); 4630 4631 if (!SOC_WARM_BOOT(unit) || 4632 !soc_feature(unit, soc_feature_tsn)) { 4633 return BCM_E_UNAVAIL; 4634 } 4635 4636 /* 1st profile should exist all the time, dont need to do wb */ 4637 if (!((sw_idx > 0) && (sw_idx < GH2_PRI_MAP_TSN_TAB_SIZE))) { 4638 LOG_ERROR(BSL_LS_BCM_TSN, 4639 (BSL_META_U(unit, 4640 "Invalid sw_idx(%d).\n"), 4641 sw_idx)); 4642 assert((sw_idx > 0) && (sw_idx < GH2_PRI_MAP_TSN_TAB_SIZE)); 4643 return BCM_E_PARAM; 4644 } 4645 4646 /* Get the flow_offset and new_int_pri from TSN_PRI_OFFSETm */ 4647 entry_idx = 0; 4648 for (hw_idx = (sw_idx << GH2_PRI_MAP_TSN_SHIFT); 4649 hw_idx < (sw_idx << GH2_PRI_MAP_TSN_SHIFT) + GH2_PRI_MAP_TSN_ENT_SIZE; 4650 hw_idx++) { 4651 4652 BCM_IF_ERROR_RETURN( 4653 soc_mem_read(unit, mem, MEM_BLOCK_ANY, hw_idx, &data)); 4654 4655 if (SOC_MEM_FIELD_VALID(unit, mem, OFFSETf)) { 4656 soc_TSN_PRI_OFFSETm_field_get(unit, &data, OFFSETf, &field_data); 4657 4658 /* Check if the current setting from HW is default setting */ 4659 if (default_offset[entry_idx] != field_data) { 4660 is_default_offset = FALSE; 4661 break; 4662 } 4663 } 4664 else { 4665 return BCM_E_INTERNAL; 4666 } 4667 4668 if (SOC_MEM_FIELD_VALID(unit, mem, INT_PRIf)) { 4669 soc_TSN_PRI_OFFSETm_field_get(unit, &data, INT_PRIf, &field_data); 4670 4671 /* Check if the current setting from HW is default setting */ 4672 if (default_new_pri[entry_idx] != field_data) { 4673 is_default_new_pri = FALSE; 4674 break; 4675 } 4676 } 4677 else { 4678 return BCM_E_INTERNAL; 4679 } 4680 entry_idx++; 4681 } 4682 4683 /* Return BCM_E_NOT_FOUND means HW doesn't exist */ 4684 if ((is_default_offset == TRUE) && (is_default_new_pri == TRUE)) { 4685 return BCM_E_NOT_FOUND; 4686 } 4687 4688 /* Return BCM_E_NONE means HW existed */ 4689 return BCM_E_NONE; 4690 #else /* BCM_WARM_BOOT_SUPPORT */ 4691 return BCM_E_UNAVAIL; 4692 #endif /* BCM_WARM_BOOT_SUPPORT */ 4693 } 4694 4695 #if defined(BCM_TSN_SR_SUPPORT) 4696 /* 4697 * Function: 4698 * bcmi_gh2_tsn_pri_map_sr_set 4699 * Purpose: 4700 * Set the Priority Map configuration to hardware 4701 * Parameters: 4702 * unit - (IN) Unit number 4703 * sw_idx - (IN) SW memory index 4704 * config - (OUT) Priority Map configuration 4705 * Returns: 4706 * BCM_E_xxx 4707 */ 4708 STATIC int 4709 bcmi_gh2_tsn_pri_map_sr_set( 4710 int unit, 4711 uint32 sw_idx, 4712 bcm_tsn_pri_map_config_t *config) 4713 { 4714 uint32 hw_idx; 4715 uint32 entry_idx; 4716 soc_mem_t mem = SR_PRI_OFFSETm; 4717 sr_pri_offset_entry_t data; 4718 uint32 field_data; 4719 int is_default_offset = TRUE, is_default_new_pri = TRUE; 4720 bcm_tsn_pri_map_entry_t *map_entry; 4721 4722 if (!soc_feature(unit, soc_feature_tsn_sr)) { 4723 return BCM_E_UNAVAIL; 4724 } 4725 4726 if (!(sw_idx < GH2_PRI_MAP_SR_TAB_SIZE)) { 4727 LOG_ERROR(BSL_LS_BCM_TSN, 4728 (BSL_META_U(unit, 4729 "Invalid sw_idx(%d).\n"), 4730 sw_idx)); 4731 assert(sw_idx < GH2_PRI_MAP_SR_TAB_SIZE); 4732 return BCM_E_PARAM; 4733 } 4734 4735 /* Parameter validation */ 4736 if (NULL == config) { 4737 return BCM_E_PARAM; 4738 } 4739 4740 /* Set the flow_offset and new_int_pri to SR_PRI_OFFSETm */ 4741 entry_idx = 0; 4742 for (hw_idx = (sw_idx << GH2_PRI_MAP_SR_SHIFT); 4743 hw_idx < (sw_idx << GH2_PRI_MAP_SR_SHIFT) + GH2_PRI_MAP_SR_ENT_SIZE; 4744 hw_idx++) { 4745 4746 map_entry = &(config->map_entries[entry_idx]); 4747 is_default_offset = 4748 (BCM_TSN_PRI_MAP_ENTRY_FLOW_OFFSET & (map_entry->flags)) ? 4749 FALSE : TRUE; 4750 is_default_new_pri = 4751 (BCM_TSN_PRI_MAP_ENTRY_NEW_INT_PRI & (map_entry->flags)) ? 4752 FALSE : TRUE; 4753 4754 BCM_IF_ERROR_RETURN( 4755 soc_mem_read(unit, mem, MEM_BLOCK_ANY, hw_idx, &data)); 4756 4757 if (SOC_MEM_FIELD_VALID(unit, mem, OFFSETf)) { 4758 if (TRUE == is_default_offset) { 4759 field_data = default_offset[entry_idx]; 4760 } 4761 else { 4762 field_data = config->map_entries[entry_idx].flow_offset; 4763 } 4764 4765 /* Check if the value fit the target field range */ 4766 BCM_IF_ERROR_RETURN 4767 (soc_mem_field32_fit( 4768 unit, mem, OFFSETf, 4769 field_data)); 4770 soc_SR_PRI_OFFSETm_field_set(unit, &data, OFFSETf, &field_data); 4771 } 4772 else { 4773 return BCM_E_INTERNAL; 4774 } 4775 4776 if (SOC_MEM_FIELD_VALID(unit, mem, INT_PRIf)) { 4777 if (TRUE == is_default_new_pri) { 4778 field_data = default_new_pri[entry_idx]; 4779 } 4780 else { 4781 field_data = config->map_entries[entry_idx].new_int_pri; 4782 } 4783 if (field_data >= GH2_PRI_MAP_SR_MAX_NEW_PRI_VALUE) { 4784 return BCM_E_PARAM; 4785 } 4786 4787 /* Check if the value fit the target field range */ 4788 BCM_IF_ERROR_RETURN 4789 (soc_mem_field32_fit( 4790 unit, mem, INT_PRIf, 4791 field_data)); 4792 soc_SR_PRI_OFFSETm_field_set(unit, &data, INT_PRIf, &field_data); 4793 } 4794 else { 4795 return BCM_E_INTERNAL; 4796 } 4797 BCM_IF_ERROR_RETURN( 4798 soc_mem_write(unit, mem, MEM_BLOCK_ALL, hw_idx, &data)); 4799 entry_idx++; 4800 } 4801 return BCM_E_NONE; 4802 } 4803 4804 /* 4805 * Function: 4806 * bcmi_gh2_tsn_pri_map_sr_get 4807 * Purpose: 4808 * Get the Priority Map configuration from hardware 4809 * Parameters: 4810 * unit - (IN) Unit number 4811 * sw_idx - (IN) SW memory index 4812 * config - (OUT) Priority Map configuration 4813 * Returns: 4814 * BCM_E_xxx 4815 */ 4816 STATIC int 4817 bcmi_gh2_tsn_pri_map_sr_get( 4818 int unit, 4819 uint32 sw_idx, 4820 bcm_tsn_pri_map_config_t *config) 4821 { 4822 uint32 hw_idx; 4823 uint32 entry_idx; 4824 soc_mem_t mem = SR_PRI_OFFSETm; 4825 sr_pri_offset_entry_t data; 4826 uint32 field_data; 4827 int is_default_offset = TRUE, is_default_new_pri = TRUE; 4828 4829 if (!soc_feature(unit, soc_feature_tsn_sr)) { 4830 return BCM_E_UNAVAIL; 4831 } 4832 4833 if (!(sw_idx < GH2_PRI_MAP_SR_TAB_SIZE)) { 4834 LOG_ERROR(BSL_LS_BCM_TSN, 4835 (BSL_META_U(unit, 4836 "Invalid sw_idx(%d).\n"), 4837 sw_idx)); 4838 assert(sw_idx < GH2_PRI_MAP_SR_TAB_SIZE); 4839 return BCM_E_PARAM; 4840 } 4841 4842 /* Parameter validation */ 4843 if (NULL == config) { 4844 return BCM_E_PARAM; 4845 } 4846 4847 /* Get the flow_offset and new_int_pri from SR_PRI_OFFSETm */ 4848 entry_idx = 0; 4849 for (hw_idx = (sw_idx << GH2_PRI_MAP_SR_SHIFT); 4850 hw_idx < (sw_idx << GH2_PRI_MAP_SR_SHIFT) + GH2_PRI_MAP_SR_ENT_SIZE; 4851 hw_idx++) { 4852 4853 BCM_IF_ERROR_RETURN( 4854 soc_mem_read(unit, mem, MEM_BLOCK_ANY, hw_idx, &data)); 4855 4856 if (SOC_MEM_FIELD_VALID(unit, mem, OFFSETf)) { 4857 soc_SR_PRI_OFFSETm_field_get(unit, &data, OFFSETf, &field_data); 4858 config->map_entries[entry_idx].flow_offset = field_data; 4859 4860 /* Check if the current setting from HW is default setting */ 4861 if (default_offset[entry_idx] != field_data) { 4862 is_default_offset = FALSE; 4863 } 4864 } 4865 else { 4866 return BCM_E_INTERNAL; 4867 } 4868 4869 if (SOC_MEM_FIELD_VALID(unit, mem, INT_PRIf)) { 4870 soc_SR_PRI_OFFSETm_field_get(unit, &data, INT_PRIf, &field_data); 4871 config->map_entries[entry_idx].new_int_pri = field_data; 4872 4873 /* Check if the current setting from HW is default setting */ 4874 if (default_new_pri[entry_idx] != field_data) { 4875 is_default_new_pri = FALSE; 4876 } 4877 } 4878 else { 4879 return BCM_E_INTERNAL; 4880 } 4881 entry_idx++; 4882 } 4883 4884 /* Set SR related setting */ 4885 config->map_type = bcmTsnPriMapTypeSrFlow; 4886 config->num_map_entries = GH2_PRI_MAP_SR_ENT_SIZE; 4887 4888 /* Check if the HW setting is default setting, and set valid flags. */ 4889 for (entry_idx = 0; 4890 entry_idx < GH2_PRI_MAP_SR_ENT_SIZE; 4891 entry_idx++) { 4892 config->map_entries[entry_idx].flags = 0; 4893 4894 if (FALSE == is_default_offset) { 4895 config->map_entries[entry_idx].flags |= 4896 BCM_TSN_PRI_MAP_ENTRY_FLOW_OFFSET; 4897 } 4898 if (FALSE == is_default_new_pri) { 4899 config->map_entries[entry_idx].flags |= 4900 BCM_TSN_PRI_MAP_ENTRY_NEW_INT_PRI; 4901 } 4902 } 4903 return BCM_E_NONE; 4904 } 4905 4906 /* 4907 * Function: 4908 * bcmi_gh2_tsn_pri_map_sr_delete 4909 * Purpose: 4910 * Delete the Priority Map configuration on hardware 4911 * Parameters: 4912 * unit - (IN) Unit number 4913 * sw_idx - (IN) SW memory index 4914 * Returns: 4915 * BCM_E_xxx 4916 */ 4917 STATIC int 4918 bcmi_gh2_tsn_pri_map_sr_delete( 4919 int unit, 4920 uint32 sw_idx) 4921 { 4922 uint32 hw_idx; 4923 uint32 entry_idx; 4924 soc_mem_t mem = SR_PRI_OFFSETm; 4925 sr_pri_offset_entry_t data; 4926 uint32 field_data; 4927 4928 LOG_VERBOSE(BSL_LS_BCM_TSN, 4929 (BSL_META_U(unit, 4930 "bcmi_gh2_tsn_pri_map_sr_delete:" 4931 "sw_idx %d\n"), 4932 sw_idx)); 4933 4934 if (!soc_feature(unit, soc_feature_tsn_sr)) { 4935 return BCM_E_UNAVAIL; 4936 } 4937 4938 /* 1st profile should exist all the time, cannot delete sw_idx 0 */ 4939 if (!((sw_idx > 0) && (sw_idx < GH2_PRI_MAP_SR_TAB_SIZE))) { 4940 LOG_ERROR(BSL_LS_BCM_TSN, 4941 (BSL_META_U(unit, 4942 "Invalid sw_idx(%d).\n"), 4943 sw_idx)); 4944 assert((sw_idx > 0) && (sw_idx < GH2_PRI_MAP_SR_TAB_SIZE)); 4945 return BCM_E_PARAM; 4946 } 4947 4948 if (sw_idx == 0) { 4949 LOG_WARN(BSL_LS_BCM_TSN, 4950 (BSL_META_U(unit, 4951 "cannot delete default profile(sw_idx = 0).\n"))); 4952 return BCM_E_NONE; 4953 } 4954 4955 /* Set the flow_offset and new_int_pri to SR_PRI_OFFSETm */ 4956 entry_idx = 0; 4957 for (hw_idx = (sw_idx << GH2_PRI_MAP_SR_SHIFT); 4958 hw_idx < (sw_idx << GH2_PRI_MAP_SR_SHIFT) + GH2_PRI_MAP_SR_ENT_SIZE; 4959 hw_idx++) { 4960 4961 BCM_IF_ERROR_RETURN( 4962 soc_mem_read(unit, mem, MEM_BLOCK_ANY, hw_idx, &data)); 4963 4964 if (SOC_MEM_FIELD_VALID(unit, mem, OFFSETf)) { 4965 field_data = default_offset[entry_idx]; 4966 soc_SR_PRI_OFFSETm_field_set(unit, &data, OFFSETf, &field_data); 4967 } 4968 else { 4969 return BCM_E_INTERNAL; 4970 } 4971 4972 if (SOC_MEM_FIELD_VALID(unit, mem, INT_PRIf)) { 4973 field_data = default_new_pri[entry_idx]; 4974 soc_SR_PRI_OFFSETm_field_set(unit, &data, INT_PRIf, &field_data); 4975 } 4976 else { 4977 return BCM_E_INTERNAL; 4978 } 4979 BCM_IF_ERROR_RETURN( 4980 soc_mem_write(unit, mem, MEM_BLOCK_ALL, hw_idx, &data)); 4981 entry_idx++; 4982 } 4983 return BCM_E_NONE; 4984 } 4985 4986 /* 4987 * Function: 4988 * bcmi_gh2_tsn_pri_map_sr_hw_index_get 4989 * Purpose: 4990 * Get HW memory base index 4991 * Parameters: 4992 * unit - (IN) Unit number 4993 * sw_idx - (IN) SW memory index 4994 * hw_index - (OUT) HW memory base index 4995 * Returns: 4996 * BCM_E_xxx 4997 */ 4998 STATIC int 4999 bcmi_gh2_tsn_pri_map_sr_hw_index_get( 5000 int unit, 5001 uint32 sw_idx, 5002 uint32 *hw_index) 5003 { 5004 if (!soc_feature(unit, soc_feature_tsn_sr)) { 5005 return BCM_E_UNAVAIL; 5006 } 5007 5008 /* Parameter validation */ 5009 if (NULL == hw_index || 5010 GH2_PRI_MAP_SR_TAB_SIZE <= sw_idx) { 5011 return BCM_E_PARAM; 5012 } 5013 *hw_index = sw_idx; 5014 LOG_VERBOSE(BSL_LS_BCM_TSN, 5015 (BSL_META_U(unit, 5016 "bcmi_gh2_tsn_pri_map_sr_hw_index_get:" 5017 "sw_idx %d, hw_index %d\n"), 5018 sw_idx, *hw_index)); 5019 return BCM_E_NONE; 5020 } 5021 5022 /* 5023 * Function: 5024 * bcmi_gh2_tsn_pri_map_sr_sw_idx_get 5025 * Purpose: 5026 * Get SW memory index 5027 * Parameters: 5028 * unit - (IN) Unit number 5029 * hw_index - (IN) HW memory base index 5030 * sw_idx - (OUT) SW memory index 5031 * Returns: 5032 * BCM_E_xxx 5033 */ 5034 STATIC int 5035 bcmi_gh2_tsn_pri_map_sr_sw_idx_get( 5036 int unit, 5037 uint32 hw_index, 5038 uint32 *sw_idx) 5039 { 5040 if (!soc_feature(unit, soc_feature_tsn_sr)) { 5041 return BCM_E_UNAVAIL; 5042 } 5043 5044 /* Parameter validation */ 5045 if (NULL == sw_idx || 5046 GH2_PRI_MAP_SR_TAB_SIZE <= hw_index) { 5047 return BCM_E_PARAM; 5048 } 5049 *sw_idx = hw_index; 5050 5051 LOG_VERBOSE(BSL_LS_BCM_TSN, 5052 (BSL_META_U(unit, 5053 "bcmi_gh2_tsn_pri_map_sr_sw_idx_get:" 5054 "hw_index %d, sw_idx %d\n"), 5055 hw_index, *sw_idx)); 5056 return BCM_E_NONE; 5057 } 5058 5059 /* 5060 * Function: 5061 * bcmi_gh2_tsn_pri_map_sr_wb_hw_existed 5062 * Purpose: 5063 * check if the HW existed value or not 5064 * Parameters: 5065 * unit - (IN) Unit being initialized 5066 * sw_idx - (IN) SW memory index 5067 * Returns: 5068 * BCM_E_NOT_FOUND means HW doesn't exist 5069 * BCM_E_NONE means HW existed 5070 */ 5071 STATIC int 5072 bcmi_gh2_tsn_pri_map_sr_wb_hw_existed( 5073 int unit, 5074 uint32 sw_idx) 5075 { 5076 #if defined(BCM_WARM_BOOT_SUPPORT) 5077 uint32 hw_idx; 5078 uint32 entry_idx; 5079 uint32 field_data; 5080 soc_mem_t mem = SR_PRI_OFFSETm; 5081 sr_pri_offset_entry_t data; 5082 int is_default_offset = TRUE, is_default_new_pri = TRUE; 5083 5084 LOG_VERBOSE(BSL_LS_BCM_TSN, 5085 (BSL_META_U(unit, 5086 "bcmi_gh2_tsn_pri_map_sr_wb_hw_existed:" 5087 "sw_idx %d\n"), 5088 sw_idx)); 5089 5090 if (!SOC_WARM_BOOT(unit) || 5091 !soc_feature(unit, soc_feature_tsn_sr)) { 5092 return BCM_E_UNAVAIL; 5093 } 5094 5095 /* 1st profile should exist all the time, cannot delete sw_idx 0 */ 5096 if (!((sw_idx > 0) && (sw_idx < GH2_PRI_MAP_SR_TAB_SIZE))) { 5097 LOG_ERROR(BSL_LS_BCM_TSN, 5098 (BSL_META_U(unit, 5099 "Invalid sw_idx(%d).\n"), 5100 sw_idx)); 5101 assert((sw_idx > 0) && (sw_idx < GH2_PRI_MAP_SR_TAB_SIZE)); 5102 return BCM_E_PARAM; 5103 } 5104 5105 /* Get the flow_offset and new_int_pri from SR_PRI_OFFSETm */ 5106 entry_idx = 0; 5107 for (hw_idx = (sw_idx << GH2_PRI_MAP_SR_SHIFT); 5108 hw_idx < (sw_idx << GH2_PRI_MAP_SR_SHIFT) + GH2_PRI_MAP_SR_ENT_SIZE; 5109 hw_idx++) { 5110 5111 BCM_IF_ERROR_RETURN( 5112 soc_mem_read(unit, mem, MEM_BLOCK_ANY, hw_idx, &data)); 5113 5114 if (SOC_MEM_FIELD_VALID(unit, mem, OFFSETf)) { 5115 soc_SR_PRI_OFFSETm_field_get(unit, &data, OFFSETf, &field_data); 5116 5117 /* check if the current setting from HW is default setting */ 5118 if (default_offset[entry_idx] != field_data) { 5119 is_default_offset = FALSE; 5120 break; 5121 } 5122 } 5123 else { 5124 return BCM_E_INTERNAL; 5125 } 5126 5127 if (SOC_MEM_FIELD_VALID(unit, mem, INT_PRIf)) { 5128 soc_SR_PRI_OFFSETm_field_get(unit, &data, INT_PRIf, &field_data); 5129 5130 /* Check if the current setting from HW is default setting */ 5131 if (default_new_pri[entry_idx] != field_data) { 5132 is_default_new_pri = FALSE; 5133 break; 5134 } 5135 } 5136 else { 5137 return BCM_E_INTERNAL; 5138 } 5139 entry_idx++; 5140 } 5141 5142 /* Return BCM_E_NOT_FOUND means HW doesn't exist */ 5143 if ((is_default_offset == TRUE) && (is_default_new_pri == TRUE)) { 5144 return BCM_E_NOT_FOUND; 5145 } 5146 5147 /* Return BCM_E_NONE means HW existed */ 5148 return BCM_E_NONE; 5149 #else /* BCM_WARM_BOOT_SUPPORT */ 5150 return BCM_E_UNAVAIL; 5151 #endif /* BCM_WARM_BOOT_SUPPORT */ 5152 } 5153 5154 #endif /* BCM_TSN_SR_SUPPORT */ 5155 5156 5157 /* 5158 * Function: 5159 * bcmi_gh2_tsn_pri_map_mtu_hw_index_get 5160 * Purpose: 5161 * Get HW memory base index 5162 * Parameters: 5163 * unit - (IN) Unit number 5164 * sw_idx - (IN) SW memory index 5165 * hw_index - (OUT) HW memory base index 5166 * Returns: 5167 * BCM_E_xxx 5168 */ 5169 STATIC int 5170 bcmi_gh2_tsn_pri_map_mtu_hw_index_get( 5171 int unit, 5172 uint32 sw_idx, 5173 uint32 *hw_index) 5174 { 5175 if (!soc_feature(unit, soc_feature_tsn_mtu_stu)) { 5176 return BCM_E_UNAVAIL; 5177 } 5178 5179 /* Parameter validation */ 5180 if (NULL == hw_index || 5181 GH2_PRI_MAP_MTU_TAB_SIZE <= sw_idx) { 5182 return BCM_E_PARAM; 5183 } 5184 *hw_index = sw_idx * GH2_PRI_MAP_MTU_ENT_SIZE; 5185 5186 LOG_VERBOSE(BSL_LS_BCM_TSN, 5187 (BSL_META_U(unit, 5188 "bcmi_gh2_tsn_pri_map_mtu_hw_index_get:" 5189 "sw_idx = %d, hw_index = %d\n"), 5190 sw_idx, *hw_index)); 5191 return BCM_E_NONE; 5192 } 5193 5194 /* 5195 * Function: 5196 * bcmi_gh2_tsn_pri_map_mtu_sw_idx_get 5197 * Purpose: 5198 * Get SW memory index 5199 * Parameters: 5200 * unit - (IN) Unit number 5201 * hw_index - (IN) HW memory base index 5202 * sw_idx - (OUT) SW memory index 5203 * Returns: 5204 * BCM_E_xxx 5205 */ 5206 STATIC int 5207 bcmi_gh2_tsn_pri_map_mtu_sw_idx_get( 5208 int unit, 5209 uint32 hw_index, 5210 uint32 *sw_idx) 5211 { 5212 if (!soc_feature(unit, soc_feature_tsn_mtu_stu)) { 5213 return BCM_E_UNAVAIL; 5214 } 5215 5216 /* Parameter validation */ 5217 if (NULL == sw_idx || 5218 GH2_PRI_MAP_MTU_MASK & hw_index || 5219 GH2_PRI_MAP_MTU_TAB_SIZE * GH2_PRI_MAP_MTU_ENT_SIZE <= hw_index) { 5220 return BCM_E_PARAM; 5221 } 5222 *sw_idx = hw_index >> GH2_PRI_MAP_MTU_SHIFT; 5223 5224 LOG_VERBOSE(BSL_LS_BCM_TSN, 5225 (BSL_META_U(unit, 5226 "bcmi_gh2_tsn_pri_map_mtu_sw_idx_get:" 5227 "hw_index %d, sw_idx %d\n"), 5228 hw_index, *sw_idx)); 5229 return BCM_E_NONE; 5230 } 5231 5232 /* 5233 * Function: 5234 * bcmi_gh2_tsn_pri_map_stu_hw_index_get 5235 * Purpose: 5236 * Get HW memory base index 5237 * Parameters: 5238 * unit - (IN) Unit number 5239 * sw_idx - (IN) SW memory index 5240 * hw_index - (OUT) HW memory base index 5241 * Returns: 5242 * BCM_E_xxx 5243 */ 5244 STATIC int 5245 bcmi_gh2_tsn_pri_map_stu_hw_index_get( 5246 int unit, 5247 uint32 sw_idx, 5248 uint32 *hw_index) 5249 { 5250 if (!soc_feature(unit, soc_feature_tsn_mtu_stu)) { 5251 return BCM_E_UNAVAIL; 5252 } 5253 5254 /* Parameter validation */ 5255 if (NULL == hw_index || 5256 GH2_PRI_MAP_STU_TAB_SIZE <= sw_idx) { 5257 return BCM_E_PARAM; 5258 } 5259 *hw_index = sw_idx * GH2_PRI_MAP_STU_ENT_SIZE; 5260 5261 LOG_VERBOSE(BSL_LS_BCM_TSN, 5262 (BSL_META_U(unit, 5263 "bcmi_gh2_tsn_pri_map_stu_hw_index_get:" 5264 "sw_idx %d, hw_index %d\n"), 5265 sw_idx, *hw_index)); 5266 return BCM_E_NONE; 5267 } 5268 5269 /* 5270 * Function: 5271 * bcmi_gh2_tsn_pri_map_stu_sw_idx_get 5272 * Purpose: 5273 * Get SW memory index 5274 * Parameters: 5275 * unit - (IN) Unit number 5276 * hw_index - (IN) HW memory base index 5277 * sw_idx - (OUT) SW memory index 5278 * Returns: 5279 * BCM_E_xxx 5280 */ 5281 STATIC int 5282 bcmi_gh2_tsn_pri_map_stu_sw_idx_get( 5283 int unit, 5284 uint32 hw_index, 5285 uint32 *sw_idx) 5286 { 5287 if (!soc_feature(unit, soc_feature_tsn_mtu_stu)) { 5288 return BCM_E_UNAVAIL; 5289 } 5290 5291 /* Parameter validation */ 5292 if (NULL == sw_idx || 5293 GH2_PRI_MAP_STU_MASK & hw_index || 5294 GH2_PRI_MAP_STU_TAB_SIZE * GH2_PRI_MAP_STU_ENT_SIZE <= hw_index) { 5295 return BCM_E_PARAM; 5296 } 5297 *sw_idx = hw_index >> GH2_PRI_MAP_STU_SHIFT; 5298 5299 LOG_VERBOSE(BSL_LS_BCM_TSN, 5300 (BSL_META_U(unit, 5301 "bcmi_gh2_tsn_pri_map_stu_sw_idx_get:" 5302 "hw_index %d, sw_idx %d\n"), 5303 hw_index, *sw_idx)); 5304 return BCM_E_NONE; 5305 } 5306 5307 /* 5308 * Function: 5309 * bcmi_gh2_tsn_control_set 5310 * Description: 5311 * Configure device-wide operation modes for TSN. 5312 * Parameters: 5313 * unit - (IN) Unit number. 5314 * type - (IN) Control type of bcm_tsn_control_t. 5315 * arg - (IN) argument to be set 5316 * Returns: 5317 * BCM_E_XXX 5318 */ 5319 STATIC int 5320 bcmi_gh2_tsn_control_set(int unit, bcm_tsn_control_t type, uint32 arg) 5321 { 5322 #if defined(BCM_TSN_SR_SUPPORT) 5323 soc_reg_t config_reg = INVALIDr; 5324 soc_mem_t config_mem = INVALIDm; 5325 soc_mem_t config_mem_egr = INVALIDm; 5326 soc_field_t config_field = INVALIDf; 5327 uint32 fldval = 0; 5328 uint32 regval = 0; 5329 int memidx = 0; 5330 uint32 entry[SOC_MAX_MEM_WORDS]; 5331 #endif /* BCM_TSN_SR_SUPPORT */ 5332 5333 LOG_VERBOSE(BSL_LS_BCM_TSN, 5334 (BSL_META_U(unit, 5335 "bcmi_esw_tsn_control_set: type = %d arg = %d\n"), 5336 type, arg)); 5337 5338 #if defined(BCM_TSN_SR_SUPPORT) 5339 if (!soc_feature(unit, soc_feature_tsn_sr)) { 5340 return (BCM_E_UNAVAIL); 5341 } 5342 #endif /* BCM_TSN_SR_SUPPORT */ 5343 5344 switch (type) { 5345 #if defined(BCM_TSN_SR_SUPPORT) 5346 case bcmTsnControlSrAgeTickInterval: 5347 if (((int)arg < 0) || (arg > 0xffff)) { 5348 return BCM_E_PARAM; 5349 } 5350 config_reg = SR_AGING_TIMERr; 5351 config_field = AGE_OUT_TIMEf; 5352 fldval = arg; 5353 if (EVENTS_BKINFO(unit) != NULL) { 5354 EVENTS_BKINFO(unit)->ageout_tick_ms = arg; 5355 } 5356 break; 5357 case bcmTsnControlSrAgeOutEnable: 5358 if (((int)arg < 0) || (arg > 1)) { 5359 return BCM_E_PARAM; 5360 } 5361 config_reg = SR_AGING_TIMERr; 5362 config_field = AGE_ENAf; 5363 fldval = arg; 5364 if (EVENTS_BKINFO(unit) != NULL) { 5365 EVENTS_BKINFO(unit)->age_enable = arg; 5366 } 5367 break; 5368 case bcmTsnControlSrSeqNumWindowResetMode: 5369 config_reg = SR_AGING_TIMERr; 5370 config_field = SN_WINDOW_RESET_TYPEf; 5371 if (arg == BCM_TSN_CONTROL_SR_SEQNUM_WINDOW_RESET_MODE_HW1) { 5372 fldval = 0; 5373 } else if (arg == BCM_TSN_CONTROL_SR_SEQNUM_WINDOW_RESET_MODE_HW2) { 5374 fldval = 1; 5375 } else if (arg == BCM_TSN_CONTROL_SR_SEQNUM_WINDOW_RESET_MODE_SW) { 5376 fldval = 2; 5377 } else { 5378 return BCM_E_PARAM; 5379 } 5380 5381 if (EVENTS_BKINFO(unit) != NULL) { 5382 EVENTS_BKINFO(unit)->window_reset_mode = arg; 5383 } 5384 break; 5385 case bcmTsnControlSrLooseOutOfOrder: 5386 if (((int)arg < 0) || (arg > 1)) { 5387 return BCM_E_PARAM; 5388 } 5389 config_reg = SR_OUT_OF_ORDER_CONTROLr; 5390 config_field = OUT_OF_ORDER_CONTROLf; 5391 fldval = arg; 5392 break; 5393 case bcmTsnControlSrHsrEthertype: 5394 if (arg > 0xffff) { 5395 return BCM_E_PARAM; 5396 } 5397 config_mem = SR_ETHERTYPESm; 5398 config_mem_egr = EGR_SR_ETHERTYPESm; 5399 config_field = HSR_ETHERTYPEf; 5400 memidx = 0; 5401 fldval = arg; 5402 break; 5403 case bcmTsnControlSrPrpEthertype: 5404 if (arg > 0xffff) { 5405 return BCM_E_PARAM; 5406 } 5407 config_mem = SR_ETHERTYPESm; 5408 config_mem_egr = EGR_SR_ETHERTYPESm; 5409 config_field = PRP_SUFFIXf; 5410 memidx = 0; 5411 fldval = arg; 5412 break; 5413 case bcmTsnControlSrDot1cbEthertype: 5414 if (arg > 0xffff) { 5415 return BCM_E_PARAM; 5416 } 5417 config_mem = SR_ETHERTYPESm; 5418 config_mem_egr = EGR_SR_ETHERTYPESm; 5419 config_field = DOT1CB_ETHERTYPEf; 5420 memidx = 0; 5421 fldval = arg; 5422 break; 5423 #endif /* BCM_TSN_SR_SUPPORT */ 5424 default: 5425 return BCM_E_PARAM; 5426 } 5427 5428 #if defined(BCM_TSN_SR_SUPPORT) 5429 if (config_reg != INVALIDr) { 5430 BCM_IF_ERROR_RETURN 5431 (soc_reg32_get(unit, config_reg, REG_PORT_ANY, 0, ®val)); 5432 soc_reg_field_set(unit, config_reg, ®val, 5433 config_field, fldval); 5434 BCM_IF_ERROR_RETURN 5435 (soc_reg32_set(unit, config_reg, REG_PORT_ANY, 0, regval)); 5436 } 5437 5438 if (config_mem != INVALIDm) { 5439 BCM_IF_ERROR_RETURN 5440 (soc_mem_read(unit, config_mem, MEM_BLOCK_ANY, memidx, &entry)); 5441 soc_mem_field32_set(unit, config_mem, &entry, config_field, fldval); 5442 BCM_IF_ERROR_RETURN 5443 (soc_mem_write(unit, config_mem, MEM_BLOCK_ALL, memidx, &entry)); 5444 } 5445 5446 if (config_mem_egr != INVALIDm) { 5447 BCM_IF_ERROR_RETURN 5448 (soc_mem_read(unit, config_mem_egr, MEM_BLOCK_ANY, 5449 memidx, &entry)); 5450 soc_mem_field32_set(unit, config_mem_egr, &entry, config_field, fldval); 5451 BCM_IF_ERROR_RETURN 5452 (soc_mem_write(unit, config_mem_egr, MEM_BLOCK_ALL, 5453 memidx, &entry)); 5454 } 5455 #endif /* BCM_TSN_SR_SUPPORT */ 5456 return BCM_E_NONE; 5457 } 5458 5459 /* 5460 * Function: 5461 * bcmi_gh2_tsn_control_get 5462 * Description: 5463 * Get the configure of device-wide TSN operation modes. 5464 * Parameters: 5465 * unit - (IN) Unit number. 5466 * type - (IN) Control type of bcm_tsn_control_t. 5467 * arg - (OUT) argument got 5468 * Returns: 5469 * BCM_E_XXX 5470 */ 5471 STATIC int 5472 bcmi_gh2_tsn_control_get(int unit, bcm_tsn_control_t type, uint32 *arg) 5473 { 5474 #if defined(BCM_TSN_SR_SUPPORT) 5475 uint32 fldval = 0; 5476 uint32 regval = 0; 5477 uint32 entry[SOC_MAX_MEM_WORDS]; 5478 #endif /* BCM_TSN_SR_SUPPORT */ 5479 5480 LOG_VERBOSE(BSL_LS_BCM_TSN, 5481 (BSL_META_U(unit, 5482 "bcmi_esw_tsn_control_get: type = %d"), 5483 type)); 5484 5485 #if defined(BCM_TSN_SR_SUPPORT) 5486 if (!soc_feature(unit, soc_feature_tsn_sr)) { 5487 return (BCM_E_UNAVAIL); 5488 } 5489 #endif /* BCM_TSN_SR_SUPPORT */ 5490 5491 /* Parameter validation */ 5492 if (NULL == arg) { 5493 return BCM_E_PARAM; 5494 } 5495 5496 switch (type) { 5497 #if defined(BCM_TSN_SR_SUPPORT) 5498 case bcmTsnControlSrAgeTickInterval: 5499 BCM_IF_ERROR_RETURN(READ_SR_AGING_TIMERr(unit, ®val)); 5500 fldval = soc_reg_field_get(unit, SR_AGING_TIMERr, 5501 regval, AGE_OUT_TIMEf); 5502 break; 5503 case bcmTsnControlSrAgeOutEnable: 5504 BCM_IF_ERROR_RETURN(READ_SR_AGING_TIMERr(unit, ®val)); 5505 fldval = soc_reg_field_get(unit, SR_AGING_TIMERr, 5506 regval, AGE_ENAf); 5507 break; 5508 case bcmTsnControlSrSeqNumWindowResetMode: 5509 BCM_IF_ERROR_RETURN(READ_SR_AGING_TIMERr(unit, ®val)); 5510 fldval = soc_reg_field_get(unit, SR_AGING_TIMERr, 5511 regval, SN_WINDOW_RESET_TYPEf); 5512 if (fldval == 0) { 5513 fldval = BCM_TSN_CONTROL_SR_SEQNUM_WINDOW_RESET_MODE_HW1; 5514 } else if (fldval == 1) { 5515 fldval = BCM_TSN_CONTROL_SR_SEQNUM_WINDOW_RESET_MODE_HW2; 5516 } else if (fldval == 2) { 5517 fldval = BCM_TSN_CONTROL_SR_SEQNUM_WINDOW_RESET_MODE_SW; 5518 } else { 5519 return BCM_E_FAIL; 5520 } 5521 break; 5522 case bcmTsnControlSrLooseOutOfOrder: 5523 BCM_IF_ERROR_RETURN(READ_SR_OUT_OF_ORDER_CONTROLr(unit, ®val)); 5524 fldval = soc_reg_field_get(unit, SR_OUT_OF_ORDER_CONTROLr, 5525 regval, OUT_OF_ORDER_CONTROLf); 5526 break; 5527 case bcmTsnControlSrHsrEthertype: 5528 BCM_IF_ERROR_RETURN 5529 (soc_mem_read(unit, SR_ETHERTYPESm, MEM_BLOCK_ANY, 0, &entry)); 5530 soc_mem_field_get(unit, SR_ETHERTYPESm, 5531 entry, HSR_ETHERTYPEf, &fldval); 5532 break; 5533 case bcmTsnControlSrPrpEthertype: 5534 BCM_IF_ERROR_RETURN 5535 (soc_mem_read(unit, SR_ETHERTYPESm, MEM_BLOCK_ANY, 0, &entry)); 5536 soc_mem_field_get(unit, SR_ETHERTYPESm, 5537 entry, PRP_SUFFIXf, &fldval); 5538 break; 5539 case bcmTsnControlSrDot1cbEthertype: 5540 BCM_IF_ERROR_RETURN 5541 (soc_mem_read(unit, SR_ETHERTYPESm, MEM_BLOCK_ANY, 0, &entry)); 5542 soc_mem_field_get(unit, SR_ETHERTYPESm, 5543 entry, DOT1CB_ETHERTYPEf, &fldval); 5544 break; 5545 #endif /* BCM_TSN_SR_SUPPORT */ 5546 default: 5547 return BCM_E_PARAM; 5548 } 5549 5550 #if defined(BCM_TSN_SR_SUPPORT) 5551 *arg = fldval; 5552 5553 LOG_VERBOSE(BSL_LS_BCM_TSN, 5554 (BSL_META_U(unit, 5555 "arg = %d\n"), 5556 *arg)); 5557 #endif /* BCM_TSN_SR_SUPPORT */ 5558 return BCM_E_NONE; 5559 } 5560 5561 /* Helper function to get the reference count of the profile memory entry */ 5562 STATIC int 5563 bcmi_gh2_tsn_mtu_profmem_refcnt_get( 5564 int unit, 5565 bcm_tsn_mtu_profile_type_t type, 5566 int index, 5567 int *ref_count) 5568 { 5569 soc_profile_mem_t *pmem; 5570 5571 if (ref_count == NULL) { 5572 return BCM_E_PARAM; 5573 } 5574 TSN_MTU_BKINFO_IS_INIT(unit, type); 5575 MTU_BKINFO_LOCK(unit); 5576 pmem = TSN_BKINFO(unit)->gh2_mtu_bk_info.mtu_profile[type]; 5577 MTU_BKINFO_UNLOCK(unit); 5578 BCM_IF_ERROR_RETURN(soc_profile_mem_ref_count_get(unit, pmem, 5579 index, ref_count)); 5580 return BCM_E_NONE; 5581 } 5582 5583 /* 5584 * Function: 5585 * bcmi_esw_tsn_mtu_profile_decode 5586 * Purpose: 5587 * Decode the profile id into 5588 * HW memory index and mtu profile type 5589 * Parameters: 5590 * unit - (IN) Unit number 5591 * mtu_profile_id - (IN) profile id 5592 * type - (OUT) Indicates ingress or egress mtu profile 5593 * index -(OUT) Indicates HW index of the mem 5594 * Returns: 5595 * BCM_E_xxx 5596 */ 5597 STATIC int 5598 bcmi_gh2_tsn_mtu_profile_decode( 5599 int unit, 5600 int mtu_profile_id, 5601 bcm_tsn_mtu_profile_type_t *type, 5602 int *index) 5603 { 5604 soc_profile_mem_table_t *table; 5605 5606 if (type == NULL || index == NULL) { 5607 return BCM_E_PARAM; 5608 } 5609 /* If it is an ingress mtu profile id */ 5610 if ((mtu_profile_id & EGR_MTU_STU_PROFILE_ID_ENCODE) == 0) { 5611 *type = bcmTsnMtuProfileTypeIngress; 5612 TSN_MTU_BKINFO_IS_INIT(unit, *type); 5613 } else { 5614 /* If it is an egress mtu profile id */ 5615 *type = bcmTsnMtuProfileTypeEgress; 5616 TSN_MTU_BKINFO_IS_INIT(unit, *type); 5617 mtu_profile_id &= ~EGR_MTU_STU_PROFILE_ID_ENCODE; 5618 } 5619 5620 /* Check whether the memory index is valid */ 5621 MTU_BKINFO_LOCK(unit); 5622 table = TSN_BKINFO(unit)->gh2_mtu_bk_info.mtu_profile[*type]->tables; 5623 if (mtu_profile_id > table->index_max || 5624 mtu_profile_id < table->index_min) { 5625 MTU_BKINFO_UNLOCK(unit); 5626 return BCM_E_PARAM; 5627 } 5628 MTU_BKINFO_UNLOCK(unit); 5629 *index = mtu_profile_id; 5630 5631 return BCM_E_NONE; 5632 } 5633 5634 5635 /* 5636 * Function: 5637 * bcmi_esw_tsn_mtu_profile_encode 5638 * Purpose: 5639 * Encode the HW memory index and type 5640 * into profile id 5641 * Parameters: 5642 * unit - (IN) Unit number 5643 * index - (IN) HW memory index 5644 * type - (IN) Indicates ingress or egress mtu profile 5645 * mtu_profile_id - (OUT) profile id 5646 * Returns: 5647 * BCM_E_xxx 5648 */ 5649 STATIC int 5650 bcmi_gh2_tsn_mtu_profile_encode( 5651 int unit, 5652 int index, 5653 bcm_tsn_mtu_profile_type_t type, 5654 int *mtu_profile_id) 5655 { 5656 soc_profile_mem_table_t *table; 5657 5658 /* The validity of the type is checked in the previous layer */ 5659 if (mtu_profile_id == NULL) { 5660 return BCM_E_PARAM; 5661 } 5662 if (TSN_BKINFO(unit) != NULL) { 5663 TSN_MTU_BKINFO_IS_INIT(unit, type); 5664 /* Check whether the memory index is valid */ 5665 MTU_BKINFO_LOCK(unit); 5666 table = TSN_BKINFO(unit)->gh2_mtu_bk_info.mtu_profile[type]->tables; 5667 if (index > table->index_max || index < table->index_min) { 5668 MTU_BKINFO_UNLOCK(unit); 5669 return BCM_E_PARAM; 5670 } 5671 MTU_BKINFO_UNLOCK(unit); 5672 } 5673 if (type == bcmTsnMtuProfileTypeIngress) { 5674 *mtu_profile_id = index; 5675 } else { 5676 *mtu_profile_id = index | EGR_MTU_STU_PROFILE_ID_ENCODE; 5677 } 5678 5679 return BCM_E_NONE; 5680 } 5681 5682 5683 /* 5684 * Function: 5685 * bcmi_gh2_tsn_mtu_profile_traverse 5686 * Purpose: 5687 * Traverse the created match config. 5688 * Parameters: 5689 * unit - (IN) Unit number 5690 * cb - (IN) Traverse call back function 5691 * user_data - (IN) User data 5692 * Returns: 5693 * BCM_E_xxx 5694 */ 5695 STATIC int 5696 bcmi_gh2_tsn_mtu_profile_traverse( 5697 int unit, 5698 bcm_tsn_mtu_profile_traverse_cb cb, 5699 void *user_data) 5700 { 5701 int i, profile_id, rv; 5702 soc_profile_mem_table_t *table; 5703 bcm_tsn_mtu_profile_type_t type; 5704 5705 if (user_data == NULL || cb == NULL) { 5706 return BCM_E_PARAM; 5707 } 5708 5709 /* Traverse on Profile Mem */ 5710 MTU_BKINFO_LOCK(unit); 5711 for (type = bcmTsnMtuProfileTypeIngress; type < bcmTsnMtuProfileTypeCount; 5712 type++) { 5713 TSN_MTU_BKINFO_IS_INIT(unit, type); 5714 table = TSN_BKINFO(unit)->gh2_mtu_bk_info.mtu_profile[type]->tables; 5715 5716 for (i = table->index_min; i <= table->index_max; i++) { 5717 bcmi_gh2_tsn_mtu_profile_encode(unit, i, type, &profile_id); 5718 /* profile id 0 is the default value, won't traverse it */ 5719 if (table->entries[i].ref_count > 0 && i != 0) { 5720 rv = cb(unit, profile_id, user_data); 5721 if (BCM_FAILURE(rv)) { 5722 MTU_BKINFO_UNLOCK(unit); 5723 return rv; 5724 } 5725 } 5726 } 5727 } 5728 MTU_BKINFO_UNLOCK(unit); 5729 5730 return BCM_E_NONE; 5731 } 5732 5733 5734 /* helper function to get the profile memory index */ 5735 STATIC int 5736 bcmi_gh2_tsn_mtu_profile_mem_idx_get( 5737 int unit, 5738 bcm_tsn_mtu_profile_type_t type, 5739 int *min, 5740 int *max) 5741 { 5742 if (min == NULL || max == NULL) { 5743 return BCM_E_PARAM; 5744 } 5745 if (type != bcmTsnMtuProfileTypeIngress && 5746 type != bcmTsnMtuProfileTypeEgress) { 5747 return BCM_E_PARAM; 5748 } 5749 *min = soc_mem_index_min(unit, gh2_mtu_profile_mem[type]); 5750 *max = soc_mem_index_max(unit, gh2_mtu_profile_mem[type]); 5751 5752 return BCM_E_NONE; 5753 } 5754 5755 /* 5756 * Function: 5757 * bcmi_gh2_tsn_mtu_profile_mem_init 5758 * Purpose: 5759 * Initiate mtu profile mem management structure 5760 * and set MTU_PROFILEm entries to zero. 5761 * Parameters: 5762 * unit - (IN) Unit number 5763 * type - (IN) Indicates ingress or egress mtu profile 5764 * Returns: 5765 * BCM_E_xxx 5766 */ 5767 STATIC int 5768 bcmi_gh2_tsn_mtu_profile_mem_init( 5769 int unit, 5770 bcm_tsn_mtu_profile_type_t type) 5771 { 5772 soc_mem_t mem; 5773 soc_mem_t mems[1]; 5774 int mem_words[1]; 5775 soc_profile_mem_t *pmem; 5776 int rv; 5777 5778 TSN_MTU_BKINFO_IS_INIT(unit, type); 5779 5780 /* Set ingress MTU profile memory HW table entries to zero */ 5781 #if defined(BCM_WARM_BOOT_SUPPORT) 5782 if (!SOC_WARM_BOOT(unit)) 5783 #endif /* BCM_WARM_BOOT_SUPPORT */ 5784 { 5785 SOC_IF_ERROR_RETURN 5786 (soc_mem_clear(unit, gh2_mtu_profile_mem[type], MEM_BLOCK_ALL, 0)); 5787 } 5788 MTU_BKINFO_LOCK(unit); 5789 pmem = TSN_BKINFO(unit)->gh2_mtu_bk_info.mtu_profile[type]; 5790 soc_profile_mem_t_init(pmem); 5791 mem = gh2_mtu_profile_mem[type]; 5792 if (SOC_MEM_IS_VALID(unit, mem)) { 5793 mems[0] = mem; 5794 if (type == bcmTsnMtuProfileTypeIngress) { 5795 mem_words[0] = BYTES2WORDS(sizeof(mtu_profile_entry_t)); 5796 } else { 5797 mem_words[0] = BYTES2WORDS(sizeof(egr_mtu_profile_entry_t)); 5798 } 5799 } else { 5800 MTU_BKINFO_UNLOCK(unit); 5801 return BCM_E_INTERNAL; 5802 } 5803 rv = soc_profile_mem_create(unit, mems, mem_words, 1, pmem); 5804 5805 MTU_BKINFO_UNLOCK(unit); 5806 return rv; 5807 } 5808 5809 /* 5810 * Function: 5811 * bcmi_gh2_tsn_mtu_profile_create 5812 * Purpose: 5813 * Create mtu profile with the config pointer 5814 * and return the assigned profile id. 5815 * Parameters: 5816 * unit - (IN) Unit number 5817 * type - (IN) Indicates ingress or egress mtu profile 5818 * config - (IN) configuration of the mtu profile 5819 * index - (OUT) HW index of ingress mtu profile 5820 * Returns: 5821 * BCM_E_xxx 5822 */ 5823 STATIC int 5824 bcmi_gh2_tsn_mtu_profile_create( 5825 int unit, 5826 bcm_tsn_mtu_profile_type_t type, 5827 bcm_tsn_mtu_config_t *config, 5828 uint32 *index) 5829 { 5830 void *entries[1]; 5831 soc_profile_mem_t *pmem; 5832 void *entry; 5833 mtu_profile_entry_t entry_i; 5834 egr_mtu_profile_entry_t entry_e; 5835 int rv; 5836 5837 if (index == NULL || config == NULL) { 5838 return BCM_E_PARAM; 5839 } 5840 TSN_MTU_BKINFO_IS_INIT(unit, type); 5841 5842 if (type == bcmTsnMtuProfileTypeIngress) { 5843 entry = &entry_i; 5844 } else { 5845 entry = &entry_e; 5846 } 5847 5848 SOC_IF_ERROR_RETURN 5849 (soc_mem_field32_fit(unit, gh2_mtu_profile_mem[type], 5850 MTU_SIZEf, config->size)); 5851 SOC_IF_ERROR_RETURN 5852 (soc_mem_field32_fit(unit, gh2_mtu_profile_mem[type], 5853 MTU_ERROR_ACTIONf, config->drop)); 5854 soc_mem_field32_set(unit, gh2_mtu_profile_mem[type], (uint32 *)entry, 5855 MTU_SIZEf, config->size); 5856 soc_mem_field32_set(unit, gh2_mtu_profile_mem[type], (uint32 *)entry, 5857 MTU_ERROR_ACTIONf, config->drop); 5858 MTU_BKINFO_LOCK(unit); 5859 pmem = TSN_BKINFO(unit)->gh2_mtu_bk_info.mtu_profile[type]; 5860 entries[0] = entry; 5861 rv = soc_profile_mem_add(unit, pmem, entries, 1, index); 5862 MTU_BKINFO_UNLOCK(unit); 5863 5864 return rv; 5865 } 5866 5867 /* 5868 * Function: 5869 * bcmi_gh2_tsn_mtu_profile_get 5870 * Purpose: 5871 * Get mtu profile configuration 5872 * with the profile id. 5873 * Parameters: 5874 * unit - (IN) Unit number 5875 * index - (IN) HW index of ingress mtu profile 5876 * type - (IN) Indicates ingress or egress mtu profile 5877 * config - (OUT) configuration of the mtu profile 5878 * Returns: 5879 * BCM_E_xxx 5880 */ 5881 STATIC int 5882 bcmi_gh2_tsn_mtu_profile_get( 5883 int unit, 5884 int index, 5885 bcm_tsn_mtu_profile_type_t type, 5886 bcm_tsn_mtu_config_t *config) 5887 { 5888 void *entries[1]; 5889 soc_profile_mem_t *pmem; 5890 void *entry; 5891 mtu_profile_entry_t entry_i; 5892 egr_mtu_profile_entry_t entry_e; 5893 5894 if (config == NULL) { 5895 return BCM_E_PARAM; 5896 } 5897 TSN_MTU_BKINFO_IS_INIT(unit, type); 5898 5899 if (type == bcmTsnMtuProfileTypeIngress) { 5900 entry = &entry_i; 5901 } else { 5902 entry = &entry_e; 5903 } 5904 MTU_BKINFO_LOCK(unit); 5905 pmem = TSN_BKINFO(unit)->gh2_mtu_bk_info.mtu_profile[type]; 5906 entries[0] = entry; 5907 BCM_IF_ERROR_RETURN(soc_profile_mem_get(unit, pmem, index, 1, entries)); 5908 if (SOC_MEM_FIELD_VALID(unit, gh2_mtu_profile_mem[type], MTU_SIZEf) && 5909 SOC_MEM_FIELD_VALID(unit, gh2_mtu_profile_mem[type], 5910 MTU_ERROR_ACTIONf)) { 5911 config->size = 5912 soc_mem_field32_get(unit, gh2_mtu_profile_mem[type], 5913 (uint32 *)entry, MTU_SIZEf); 5914 config->drop = 5915 soc_mem_field32_get(unit, gh2_mtu_profile_mem[type], 5916 (uint32 *)entry, MTU_ERROR_ACTIONf); 5917 } else { 5918 MTU_BKINFO_UNLOCK(unit); 5919 return BCM_E_INTERNAL; 5920 } 5921 MTU_BKINFO_UNLOCK(unit); 5922 return BCM_E_NONE; 5923 } 5924 5925 /* 5926 * Function: 5927 * bcmi_gh2_tsn_ingress_mtu_profile_set 5928 * Purpose: 5929 * Set mtu profile with the profile id 5930 * and config parameter. 5931 * Parameters: 5932 * unit - (IN) Unit number 5933 * index - (IN) HW index of ingress mtu profile 5934 * type - (IN) Indicates ingress or egress mtu profile 5935 * config - (IN) configuration of the mtu profile 5936 * Returns: 5937 * BCM_E_xxx 5938 */ 5939 STATIC int 5940 bcmi_gh2_tsn_mtu_profile_set( 5941 int unit, 5942 int index, 5943 bcm_tsn_mtu_profile_type_t type, 5944 bcm_tsn_mtu_config_t *config) 5945 { 5946 int idx, profile_idx, rv; 5947 void *entries[1]; 5948 bcm_tsn_mtu_config_t config_repl; 5949 soc_profile_mem_table_t *table; 5950 soc_profile_mem_t *pmem; 5951 void *entry; 5952 mtu_profile_entry_t entry_i; 5953 egr_mtu_profile_entry_t entry_e; 5954 5955 if (config == NULL) { 5956 return BCM_E_PARAM; 5957 } 5958 TSN_MTU_BKINFO_IS_INIT(unit, type); 5959 5960 /* 5961 * Search for whether replicated profile mem config exist, 5962 * if existed return BCM_E_UNAVAIL 5963 */ 5964 bcm_tsn_mtu_config_t_init(&config_repl); 5965 MTU_BKINFO_LOCK(unit); 5966 table = TSN_BKINFO(unit)->gh2_mtu_bk_info.mtu_profile[type]->tables; 5967 for (idx = table->index_min; idx <= table->index_max; idx++) { 5968 bcmi_gh2_tsn_mtu_profile_encode(unit, idx, type, &profile_idx); 5969 bcmi_gh2_tsn_mtu_profile_get(unit, idx, type, &config_repl); 5970 if ((config_repl.size == config->size) && 5971 (config_repl.drop == config->drop)) { 5972 LOG_WARN(BSL_LS_BCMAPI_TSN, 5973 (BSL_META_U(unit, 5974 "config already existed, found" 5975 " mtu profile id(%d)\n"), profile_idx)); 5976 MTU_BKINFO_UNLOCK(unit); 5977 return BCM_E_EXISTS; 5978 } 5979 } 5980 MTU_BKINFO_UNLOCK(unit); 5981 5982 SOC_IF_ERROR_RETURN 5983 (soc_mem_field32_fit(unit, gh2_mtu_profile_mem[type], 5984 MTU_SIZEf, config->size)); 5985 SOC_IF_ERROR_RETURN 5986 (soc_mem_field32_fit(unit, gh2_mtu_profile_mem[type], MTU_ERROR_ACTIONf, 5987 config->drop)); 5988 5989 if (type == bcmTsnMtuProfileTypeIngress) { 5990 entry = &entry_i; 5991 } else { 5992 entry = &entry_e; 5993 } 5994 5995 if (SOC_MEM_FIELD_VALID(unit, gh2_mtu_profile_mem[type], MTU_SIZEf) && 5996 SOC_MEM_FIELD_VALID(unit, gh2_mtu_profile_mem[type], 5997 MTU_ERROR_ACTIONf)) { 5998 soc_mem_field32_set(unit, gh2_mtu_profile_mem[type], 5999 entry, MTU_SIZEf, config->size); 6000 soc_mem_field32_set(unit, gh2_mtu_profile_mem[type], entry, 6001 MTU_ERROR_ACTIONf, config->drop); 6002 } else { 6003 return BCM_E_INTERNAL; 6004 } 6005 MTU_BKINFO_LOCK(unit); 6006 pmem = TSN_BKINFO(unit)->gh2_mtu_bk_info.mtu_profile[type]; 6007 entries[0] = entry; 6008 rv = soc_profile_mem_set(unit, pmem, entries, index); 6009 MTU_BKINFO_UNLOCK(unit); 6010 6011 return rv; 6012 } 6013 6014 /* 6015 * Function: 6016 * bcmi_gh2_tsn_mtu_profile_destroy 6017 * Purpose: 6018 * Clear the mtu profile with the profile id 6019 * Parameters: 6020 * unit - (IN) Unit number 6021 * type - (IN) Indicates ingress or egress mtu profile 6022 * index - (IN) Indicated the ingress mtu profile entry 6023 * Returns: 6024 * BCM_E_xxx 6025 */ 6026 STATIC int 6027 bcmi_gh2_tsn_mtu_profile_destroy( 6028 int unit, 6029 bcm_tsn_mtu_profile_type_t type, 6030 int index) 6031 { 6032 uint32 buf; 6033 soc_profile_mem_t *pmem; 6034 void *entry; 6035 mtu_profile_entry_t entry_i; 6036 egr_mtu_profile_entry_t entry_e; 6037 int rv; 6038 6039 TSN_MTU_BKINFO_IS_INIT(unit, type); 6040 if (type == bcmTsnMtuProfileTypeIngress) { 6041 entry = &entry_i; 6042 } else { 6043 entry = &entry_e; 6044 } 6045 MTU_BKINFO_LOCK(unit); 6046 pmem = TSN_BKINFO(unit)->gh2_mtu_bk_info.mtu_profile[type]; 6047 rv = soc_profile_mem_delete(unit, pmem, index); 6048 MTU_BKINFO_UNLOCK(unit); 6049 BCM_IF_ERROR_RETURN(rv); 6050 6051 /* clear the HW table to zero */ 6052 buf = 0x00000000; 6053 SOC_IF_ERROR_RETURN(soc_mem_read(unit, gh2_mtu_profile_mem[type], 6054 MEM_BLOCK_ANY, index, entry)); 6055 soc_mem_field_set(unit, gh2_mtu_profile_mem[type], 6056 (uint32 *)entry, MTU_SIZEf, &buf); 6057 soc_mem_field_set(unit, gh2_mtu_profile_mem[type], (uint32 *)entry, 6058 MTU_ERROR_ACTIONf, &buf); 6059 SOC_IF_ERROR_RETURN( 6060 soc_mem_write(unit, gh2_mtu_profile_mem[type], MEM_BLOCK_ALL, 6061 index, entry)); 6062 6063 return BCM_E_NONE; 6064 } 6065 6066 /* 6067 * Function: 6068 * bcmi_gh2_tsn_ingress_mtu_config_set 6069 * Purpose: 6070 * Set the priority of source ingress 6071 * mtu profile index. 6072 * Parameters: 6073 * unit - (IN) Unit number 6074 * config - (IN) Configuration of the mtu profile priority 6075 * Returns: 6076 * BCM_E_xxx 6077 */ 6078 STATIC int 6079 bcmi_gh2_tsn_ingress_mtu_config_set( 6080 int unit, 6081 bcm_tsn_ingress_mtu_config_t *config) 6082 { 6083 uint32 i, reg_val, val; 6084 int user_valid[bcmTsnMtuSourceCount]; 6085 6086 if (config == NULL) { 6087 return BCM_E_PARAM; 6088 } 6089 /* source_order_count is mandatory to set as bcmTsnMtuSourceCount */ 6090 if (config->source_order_count != bcmTsnMtuSourceCount) { 6091 return BCM_E_PARAM; 6092 } 6093 for (i = 0; i < config->source_order_count; i++) { 6094 user_valid[i] = 0; 6095 } 6096 /* Check the user config is correct */ 6097 for (i = 0; i < config->source_order_count; i++) { 6098 switch (config->source_order[i]) { 6099 case bcmTsnMtuSourceTsnFlow: 6100 user_valid[bcmTsnMtuSourceTsnFlow]++; 6101 break; 6102 case bcmTsnMtuSourceSrFlow: 6103 user_valid[bcmTsnMtuSourceSrFlow]++; 6104 break; 6105 case bcmTsnMtuSourcePort: 6106 user_valid[bcmTsnMtuSourcePort]++; 6107 break; 6108 case bcmTsnMtuSourceFieldLookup: 6109 user_valid[bcmTsnMtuSourceFieldLookup]++; 6110 break; 6111 default: 6112 return BCM_E_PARAM; 6113 } 6114 } 6115 for (i = 0; i < config->source_order_count; i++) { 6116 if (user_valid[i] != 1) { 6117 return BCM_E_PARAM; 6118 } 6119 } 6120 /* 6121 * higher value in the register field means higher priority, and less 6122 * array index in the source_order means higher priority 6123 */ 6124 BCM_IF_ERROR_RETURN(READ_MTU_PRIORITYr(unit, ®_val)); 6125 for (i = 0; i < config->source_order_count; i++) { 6126 val = bcmTsnMtuSourceCount - 1 - i; 6127 switch (config->source_order[i]) { 6128 case bcmTsnMtuSourceTsnFlow: 6129 soc_reg_field_set(unit, MTU_PRIORITYr, ®_val, 6130 L2_TSN_PRIORITYf, val); 6131 break; 6132 case bcmTsnMtuSourceSrFlow: 6133 soc_reg_field_set(unit, MTU_PRIORITYr, ®_val, 6134 L2_SR_PRIORITYf, val); 6135 break; 6136 case bcmTsnMtuSourcePort: 6137 soc_reg_field_set(unit, MTU_PRIORITYr, ®_val, 6138 PORT_PRIORITYf, val); 6139 break; 6140 case bcmTsnMtuSourceFieldLookup: 6141 soc_reg_field_set(unit, MTU_PRIORITYr, ®_val, 6142 VFP_PRIORITYf, val); 6143 break; 6144 default: 6145 return BCM_E_PARAM; 6146 } 6147 } 6148 BCM_IF_ERROR_RETURN(WRITE_MTU_PRIORITYr(unit, reg_val)); 6149 6150 return BCM_E_NONE; 6151 } 6152 6153 /* 6154 * Function: 6155 * bcmi_gh2_tsn_ingress_mtu_config_get 6156 * Purpose: 6157 * Get the priority of source ingress 6158 * mtu profile index. 6159 * Parameters: 6160 * unit - (IN) Unit number 6161 * config - (OUT) Configuration of the mtu profile priority 6162 * Returns: 6163 * BCM_E_xxx 6164 */ 6165 STATIC int 6166 bcmi_gh2_tsn_ingress_mtu_config_get( 6167 int unit, 6168 bcm_tsn_ingress_mtu_config_t *config) 6169 { 6170 int i; 6171 uint32 reg_val, val; 6172 static const soc_field_t mtu_pri_field[] = { 6173 L2_TSN_PRIORITYf, L2_SR_PRIORITYf, 6174 PORT_PRIORITYf, VFP_PRIORITYf 6175 }; 6176 static const bcm_tsn_mtu_source_t mtu_src[] = { 6177 bcmTsnMtuSourceTsnFlow, bcmTsnMtuSourceSrFlow, 6178 bcmTsnMtuSourcePort, bcmTsnMtuSourceFieldLookup 6179 }; 6180 6181 if (config == NULL) { 6182 return BCM_E_PARAM; 6183 } 6184 /* 6185 * higher value in the register field means higher priority, and less 6186 * array index in the source_order means higher priority 6187 */ 6188 6189 config->source_order_count = bcmTsnMtuSourceCount; 6190 BCM_IF_ERROR_RETURN(READ_MTU_PRIORITYr(unit, ®_val)); 6191 for (i = 0; i < config->source_order_count; i++) { 6192 if (SOC_REG_FIELD_VALID(unit, MTU_PRIORITYr, mtu_pri_field[i])) { 6193 val = soc_reg_field_get(unit, MTU_PRIORITYr, 6194 reg_val, mtu_pri_field[i]); 6195 } else { 6196 return BCM_E_INTERNAL; 6197 } 6198 if (val < bcmTsnMtuSourceCount) { 6199 config->source_order[(bcmTsnMtuSourceCount - 1) - val] = 6200 mtu_src[i]; 6201 } else { 6202 return BCM_E_INTERNAL; 6203 } 6204 } 6205 return BCM_E_NONE; 6206 } 6207 6208 /* Helper function to setup EGR_MTU_CHECKm */ 6209 STATIC int 6210 bcmi_gh2_tsn_port_control_egress_mtu_set( 6211 int unit, 6212 bcm_gport_t gport, 6213 bcm_tsn_pri_map_config_t *config) 6214 { 6215 bcm_port_t port; 6216 int pri, index, index_base, egr_prof_index; 6217 bcm_tsn_mtu_profile_type_t type; 6218 egr_mtu_check_entry_t egr_mtu; 6219 6220 if (config == NULL) { 6221 return BCM_E_PARAM; 6222 } 6223 6224 if (config->map_type != bcmTsnPriMapTypeEgressMtuProfile) { 6225 return BCM_E_PARAM; 6226 } 6227 /* Validate and convert gport to local port */ 6228 BCM_IF_ERROR_RETURN( 6229 _bcm_esw_port_gport_validate(unit, gport, &port)); 6230 6231 if (port < 0 || port >= GH2_LOGIC_PORT_MAX_NUM) { 6232 return BCM_E_PARAM; 6233 } 6234 6235 index_base = port * EGRESS_MTU_STU_INT_PRI_NUM; 6236 sal_memset(&egr_mtu, 0, sizeof(egr_mtu)); 6237 for (pri = 0; pri < config->num_map_entries; pri++) { 6238 index = index_base + pri; 6239 SOC_IF_ERROR_RETURN( 6240 soc_mem_read(unit, EGR_MTU_CHECKm, MEM_BLOCK_ANY, index, 6241 &egr_mtu)); 6242 BCM_IF_ERROR_RETURN(bcmi_gh2_tsn_mtu_profile_decode( 6243 unit, config->map_entries[pri].profile_id, 6244 &type, &egr_prof_index)); 6245 soc_mem_field32_set(unit, EGR_MTU_CHECKm, &egr_mtu, 6246 MTU_PROFILE_INDEXf, egr_prof_index); 6247 SOC_IF_ERROR_RETURN( 6248 soc_mem_write(unit, EGR_MTU_CHECKm, MEM_BLOCK_ALL, index, 6249 &egr_mtu)); 6250 } 6251 6252 return BCM_E_NONE; 6253 } 6254 6255 /* Helper function to set PORT_TABm MTU_PROFILE_INDEXf */ 6256 STATIC int 6257 bcmi_gh2_tsn_port_control_ingress_mtu_set( 6258 int unit, 6259 bcm_gport_t gport, 6260 int index) 6261 { 6262 bcm_port_t port; 6263 sr_port_table_entry_t mtu_profile; 6264 6265 /* Validate and convert gport to local port */ 6266 BCM_IF_ERROR_RETURN( 6267 _bcm_esw_port_gport_validate(unit, gport, &port)); 6268 6269 if (port < 0 || port >= GH2_LOGIC_PORT_MAX_NUM) { 6270 return BCM_E_PARAM; 6271 } 6272 /* check whether index is in the valid range */ 6273 SOC_IF_ERROR_RETURN( 6274 soc_mem_field32_fit(unit, SR_PORT_TABLEm, MTU_PROFILE_INDEXf, index)); 6275 SOC_IF_ERROR_RETURN( 6276 soc_mem_read(unit, SR_PORT_TABLEm, MEM_BLOCK_ANY, port, 6277 &mtu_profile)); 6278 soc_mem_field32_set(unit, SR_PORT_TABLEm, &mtu_profile, 6279 MTU_PROFILE_INDEXf, index); 6280 SOC_IF_ERROR_RETURN( 6281 soc_mem_write(unit, SR_PORT_TABLEm, MEM_BLOCK_ALL, port, 6282 &mtu_profile)); 6283 6284 return BCM_E_NONE; 6285 } 6286 6287 /* Helper function to get PORT_TABm MTU_PROFILE_INDEXf */ 6288 STATIC int 6289 bcmi_gh2_tsn_port_control_ingress_mtu_get( 6290 int unit, 6291 bcm_gport_t gport, 6292 int *index) 6293 { 6294 bcm_port_t port; 6295 sr_port_table_entry_t mtu_profile; 6296 6297 /* Validate and convert gport to local port */ 6298 BCM_IF_ERROR_RETURN( 6299 _bcm_esw_port_gport_validate(unit, gport, &port)); 6300 6301 if (port < 0 || port >= GH2_LOGIC_PORT_MAX_NUM || index == NULL) { 6302 return BCM_E_PARAM; 6303 } 6304 6305 SOC_IF_ERROR_RETURN( 6306 soc_mem_read(unit, SR_PORT_TABLEm, MEM_BLOCK_ANY, port, 6307 &mtu_profile)); 6308 *index = soc_mem_field32_get(unit, SR_PORT_TABLEm, &mtu_profile, 6309 MTU_PROFILE_INDEXf); 6310 6311 return BCM_E_NONE; 6312 } 6313 6314 /* Helper function to get the reference count of the profile memory entry */ 6315 STATIC int 6316 bcmi_gh2_tsn_stu_profmem_refcnt_get( 6317 int unit, 6318 bcm_tsn_stu_profile_type_t type, 6319 int index, 6320 int *ref_count) 6321 { 6322 soc_profile_mem_t *pmem; 6323 6324 if (ref_count == NULL) { 6325 return BCM_E_PARAM; 6326 } 6327 TSN_STU_BKINFO_IS_INIT(unit, type); 6328 STU_BKINFO_LOCK(unit); 6329 pmem = TSN_BKINFO(unit)->gh2_stu_bk_info.stu_profile[type]; 6330 STU_BKINFO_UNLOCK(unit); 6331 BCM_IF_ERROR_RETURN(soc_profile_mem_ref_count_get(unit, pmem, 6332 index, ref_count)); 6333 return BCM_E_NONE; 6334 } 6335 6336 /* 6337 * Function: 6338 * bcmi_esw_tsn_stu_profile_decode 6339 * Purpose: 6340 * Decode the profile id into 6341 * HW memory index and stu profile type 6342 * Parameters: 6343 * unit - (IN) Unit number 6344 * stu_profile_id - (IN) profile id 6345 * type - (OUT) Indicates ingress or egress stu profile 6346 * index -(OUT) Indicates HW index of the mem 6347 * Returns: 6348 * BCM_E_xxx 6349 */ 6350 STATIC int 6351 bcmi_gh2_tsn_stu_profile_decode( 6352 int unit, 6353 int stu_profile_id, 6354 bcm_tsn_stu_profile_type_t *type, 6355 int *index) 6356 { 6357 soc_profile_mem_table_t *table; 6358 6359 if (type == NULL || index == NULL) { 6360 return BCM_E_PARAM; 6361 } 6362 /* If it is an ingress stu profile id */ 6363 if ((stu_profile_id & EGR_MTU_STU_PROFILE_ID_ENCODE) == 0) { 6364 *type = bcmTsnStuProfileTypeIngress; 6365 TSN_STU_BKINFO_IS_INIT(unit, *type); 6366 } else { 6367 /* If it is an egress stu profile id */ 6368 *type = bcmTsnStuProfileTypeEgress; 6369 TSN_STU_BKINFO_IS_INIT(unit, *type); 6370 stu_profile_id &= ~EGR_MTU_STU_PROFILE_ID_ENCODE; 6371 } 6372 6373 /* Check whether the memory index is valid */ 6374 STU_BKINFO_LOCK(unit); 6375 table = TSN_BKINFO(unit)->gh2_stu_bk_info.stu_profile[*type]->tables; 6376 if (stu_profile_id > table->index_max || 6377 stu_profile_id < table->index_min) { 6378 STU_BKINFO_UNLOCK(unit); 6379 return BCM_E_PARAM; 6380 } 6381 STU_BKINFO_UNLOCK(unit); 6382 *index = stu_profile_id; 6383 6384 return BCM_E_NONE; 6385 } 6386 6387 #if defined(BCM_TSN_SR_SUPPORT) 6388 6389 /* 6390 * Function: 6391 * bcmi_gh2_tsn_sr_auto_learn_table_size_get 6392 * Purpose: 6393 * Get the table size for auto learn 6394 * Parameters: 6395 * unit - (IN) Unit number 6396 * table_size - (OUT) table size 6397 * Returns: 6398 * BCM_E_xxx 6399 */ 6400 STATIC int 6401 bcmi_gh2_tsn_sr_auto_learn_table_size_get( 6402 int unit, 6403 uint32 *table_size) 6404 { 6405 /* Parameter NULL error handling */ 6406 if (NULL == table_size) { 6407 return BCM_E_PARAM; 6408 } 6409 6410 /* 6411 * SR Auto Learn table 6412 * Since each SR group need 3 ports at least, 6413 * divide with 3 is a reasonable total flow size 6414 */ 6415 *table_size = NUM_PORT(unit) / 3; 6416 return BCM_E_NONE; 6417 } 6418 6419 /* Per port check if SR is enabled and port role is correct matched. */ 6420 STATIC int 6421 bcmi_gh2_tsn_sr_auto_learn_group_port_config_check( 6422 int unit, 6423 bcmi_tsn_sr_auto_learn_group_port_type_t group_port_type, 6424 bcm_gport_t gport) 6425 { 6426 bcm_tsn_sr_port_config_t org_config; 6427 6428 GH2_TSN_FUNCTION_TRACE(unit, "IN"); 6429 6430 LOG_VERBOSE(BSL_LS_BCM_TSN, 6431 (BSL_META_U(unit, 6432 "%2d "), gport)); 6433 6434 if (!soc_feature(unit, soc_feature_tsn_sr) || 6435 !soc_feature(unit, soc_feature_tsn_sr_auto_learn)) { 6436 return BCM_E_UNAVAIL; 6437 } 6438 6439 BCM_IF_ERROR_RETURN( 6440 bcmi_gh2_tsn_sr_port_config_get(unit, gport, &org_config)); 6441 6442 /* Port pre-configuration check */ 6443 if (bcmTsnSrPortTypeNone == org_config.port_type) { 6444 return BCM_E_CONFIG; 6445 } else if ((bcmi_sr_auto_learn_group_l2mc == group_port_type) && 6446 (org_config.interlink_role != 0)) { 6447 return BCM_E_CONFIG; 6448 } 6449 6450 GH2_TSN_FUNCTION_TRACE(unit, "OUT"); 6451 return BCM_E_NONE; 6452 } 6453 6454 /* 6455 * Function: 6456 * bcmi_gh2_tsn_sr_auto_learn_group_port_set 6457 * Purpose: 6458 * Set value to the ports of given bitmap 6459 * Parameters: 6460 * unit - (IN) Unit number 6461 * group_port_type - (IN) SR Auto Learn Group port type 6462 * port_pbmp - (IN) port bitmap 6463 * val - (IN) value to write 6464 * Returns: 6465 * BCM_E_XXX 6466 */ 6467 STATIC int 6468 bcmi_gh2_tsn_sr_auto_learn_group_port_set( 6469 int unit, 6470 bcmi_tsn_sr_auto_learn_group_port_type_t group_port_type, 6471 bcm_pbmp_t port_pbmp, 6472 int val) 6473 { 6474 sr_port_table_entry_t data; 6475 soc_mem_t mem = INVALIDm; 6476 soc_field_t port_field = INVALIDf; 6477 bcm_port_t port; 6478 bcm_gport_t gport; 6479 int rv; 6480 int ptab; 6481 /* Port tables to write */ 6482 const soc_mem_t mem_list[] = { 6483 SR_PORT_TABLEm, 6484 SR_LPORT_TABm 6485 }; 6486 int mem_idx; 6487 bcm_module_t my_modid = -1; 6488 int src_trk_idx = 0; /* Source Trunk table index.*/ 6489 uint32 mem_entry[SOC_MAX_MEM_WORDS]; 6490 6491 BCM_IF_ERROR_RETURN( 6492 bcm_esw_stk_my_modid_get(unit, &my_modid)); 6493 6494 GH2_TSN_FUNCTION_TRACE(unit, "IN"); 6495 6496 LOG_VERBOSE(BSL_LS_BCM_TSN, 6497 (BSL_META_U(unit, 6498 "group_port_type %d , val %d\n"), 6499 group_port_type, val)); 6500 6501 if (!soc_feature(unit, soc_feature_tsn_sr) || 6502 !soc_feature(unit, soc_feature_tsn_sr_auto_learn)) { 6503 return BCM_E_UNAVAIL; 6504 } 6505 6506 if (group_port_type == bcmi_sr_auto_learn_group_l2mc) { 6507 port_field = L2MCf; 6508 } else if (group_port_type == bcmi_sr_auto_learn_group_macp) { 6509 port_field = SR_MAC_PROXY_PROFILE_PTRf; 6510 } else { 6511 return BCM_E_PARAM; 6512 } 6513 6514 for (ptab = 0; ptab < COUNTOF(mem_list); ptab++) { 6515 mem = mem_list[ptab]; 6516 if (!SOC_MEM_IS_VALID(unit, mem) || 6517 !SOC_MEM_FIELD_VALID(unit, mem, port_field)) { 6518 return BCM_E_INTERNAL; 6519 } 6520 6521 /* Check if the value fit the target field range */ 6522 BCM_IF_ERROR_RETURN 6523 (soc_mem_field32_fit( 6524 unit, mem, port_field, (uint32)val)); 6525 } 6526 6527 for (ptab = 0; ptab < COUNTOF(mem_list); ptab++) { 6528 mem = mem_list[ptab]; 6529 PBMP_ITER(port_pbmp, port) { 6530 LOG_VERBOSE(BSL_LS_BCM_TSN, 6531 (BSL_META_U(unit, 6532 "port %2d: "), port)); 6533 /* convert port to gport */ 6534 BCM_IF_ERROR_RETURN( 6535 bcm_esw_port_gport_get(unit, port, &gport)); 6536 6537 /* Port SR related config check */ 6538 BCM_IF_ERROR_RETURN( 6539 bcmi_gh2_tsn_sr_auto_learn_group_port_config_check( 6540 unit, group_port_type, gport)); 6541 6542 if (mem == SR_LPORT_TABm) { 6543 BCM_IF_ERROR_RETURN( 6544 _bcm_esw_src_mod_port_table_index_get(unit, my_modid, 6545 port, &src_trk_idx)); 6546 BCM_IF_ERROR_RETURN( 6547 soc_mem_read(unit, SOURCE_TRUNK_MAP_TABLEm, MEM_BLOCK_ANY, 6548 src_trk_idx, mem_entry)); 6549 6550 mem_idx = soc_mem_field32_get(unit, SOURCE_TRUNK_MAP_TABLEm, 6551 mem_entry, LPORT_PROFILE_IDXf); 6552 } else { 6553 mem_idx = port; 6554 } 6555 MEM_LOCK(unit, mem); 6556 rv = soc_mem_read(unit, mem, MEM_BLOCK_ANY, mem_idx, &data); 6557 if (BCM_FAILURE(rv)) { 6558 LOG_ERROR(BSL_LS_BCM_TSN, 6559 (BSL_META_U(unit, "Failed to read mem[%s]"), 6560 SOC_MEM_NAME(unit, mem))); 6561 MEM_UNLOCK(unit, mem); 6562 return rv; 6563 } 6564 soc_mem_field32_set(unit, mem, &data, port_field, (uint32)val); 6565 rv = soc_mem_write(unit, mem, MEM_BLOCK_ALL, mem_idx, &data); 6566 if (BCM_FAILURE(rv)) { 6567 LOG_ERROR(BSL_LS_BCM_TSN, 6568 (BSL_META_U(unit, "Failed to write mem[%s]"), 6569 SOC_MEM_NAME(unit, mem))); 6570 MEM_UNLOCK(unit, mem); 6571 return rv; 6572 } 6573 MEM_UNLOCK(unit, mem); 6574 } 6575 } 6576 GH2_TSN_FUNCTION_TRACE(unit, "OUT"); 6577 return BCM_E_NONE; 6578 } 6579 6580 /* 6581 * Function: 6582 * bcmi_gh2_tsn_sr_auto_learn_group_port_delete 6583 * Purpose: 6584 * Reset the value of the ports of given bitmap 6585 * Parameters: 6586 * unit - (IN) Unit number 6587 * group_port_type - (IN) SR Auto Learn Group port type 6588 * port_pbmp - (IN) port bitmap 6589 * Returns: 6590 * BCM_E_XXX 6591 */ 6592 STATIC int 6593 bcmi_gh2_tsn_sr_auto_learn_group_port_delete( 6594 int unit, 6595 bcmi_tsn_sr_auto_learn_group_port_type_t group_port_type, 6596 bcm_pbmp_t port_pbmp) 6597 { 6598 bcm_port_t port; 6599 int val; 6600 6601 GH2_TSN_FUNCTION_TRACE(unit, "IN"); 6602 6603 LOG_VERBOSE(BSL_LS_BCM_TSN, 6604 (BSL_META_U(unit, "group_port_type %d "), group_port_type)); 6605 6606 PBMP_ITER(port_pbmp, port) { 6607 LOG_VERBOSE(BSL_LS_BCM_TSN, 6608 (BSL_META_U(unit, "%2d "), port)); 6609 } 6610 6611 if (!soc_feature(unit, soc_feature_tsn_sr) || 6612 !soc_feature(unit, soc_feature_tsn_sr_auto_learn)) { 6613 return BCM_E_UNAVAIL; 6614 } 6615 6616 val = ((group_port_type == bcmi_sr_auto_learn_group_l2mc) ? 6617 GH2_SR_AUTO_LEARN_GROUP_PORTS_L2MC_DEFAULT_VALUE : 6618 GH2_SR_AUTO_LEARN_GROUP_PORTS_MACP_DEFAULT_VALUE); 6619 6620 BCM_IF_ERROR_RETURN( 6621 bcmi_gh2_tsn_sr_auto_learn_group_port_set( 6622 unit, group_port_type, port_pbmp, 6623 val)); 6624 GH2_TSN_FUNCTION_TRACE(unit, "OUT"); 6625 return BCM_E_NONE; 6626 } 6627 6628 /* 6629 * Function: 6630 * bcmi_gh2_tsn_sr_auto_learn_group_port_reset_all 6631 * Purpose: 6632 * Reset the port value for all ports 6633 * Parameters: 6634 * unit - (IN) Unit number 6635 * Returns: 6636 * BCM_E_XXX 6637 */ 6638 STATIC int 6639 bcmi_gh2_tsn_sr_auto_learn_group_port_reset_all( 6640 int unit) 6641 { 6642 sr_port_table_entry_t data; 6643 soc_mem_t mem = INVALIDm; 6644 bcm_port_t port; 6645 bcm_pbmp_t ports_pbmp; 6646 int rv; 6647 int ptab; 6648 /* Port tables to write */ 6649 const soc_mem_t mem_list[] = { 6650 SR_PORT_TABLEm, 6651 SR_LPORT_TABm 6652 }; 6653 int mem_idx; 6654 bcm_module_t my_modid = -1; 6655 int src_trk_idx = 0; /* Source Trunk table index.*/ 6656 uint32 mem_entry[SOC_MAX_MEM_WORDS]; 6657 6658 BCM_IF_ERROR_RETURN( 6659 bcm_esw_stk_my_modid_get(unit, &my_modid)); 6660 6661 GH2_TSN_FUNCTION_TRACE(unit, "IN"); 6662 6663 if (!soc_feature(unit, soc_feature_tsn_sr) || 6664 !soc_feature(unit, soc_feature_tsn_sr_auto_learn)) { 6665 return BCM_E_UNAVAIL; 6666 } 6667 6668 for (ptab = 0; ptab < COUNTOF(mem_list); ptab++) { 6669 mem = mem_list[ptab]; 6670 if (!SOC_MEM_IS_VALID(unit, mem) || 6671 !SOC_MEM_FIELD_VALID(unit, mem, L2MCf) || 6672 !SOC_MEM_FIELD_VALID(unit, mem, SR_MAC_PROXY_PROFILE_PTRf)) { 6673 return BCM_E_INTERNAL; 6674 } 6675 } 6676 6677 BCM_PBMP_ASSIGN(ports_pbmp, PBMP_PORT_ALL(unit)); 6678 6679 for (ptab = 0; ptab < COUNTOF(mem_list); ptab++) { 6680 mem = mem_list[ptab]; 6681 PBMP_ITER(ports_pbmp, port) { 6682 if (mem == SR_LPORT_TABm) { 6683 BCM_IF_ERROR_RETURN( 6684 _bcm_esw_src_mod_port_table_index_get(unit, my_modid, 6685 port, &src_trk_idx)); 6686 BCM_IF_ERROR_RETURN( 6687 soc_mem_read(unit, SOURCE_TRUNK_MAP_TABLEm, MEM_BLOCK_ANY, 6688 src_trk_idx, mem_entry)); 6689 6690 mem_idx = soc_mem_field32_get(unit, SOURCE_TRUNK_MAP_TABLEm, 6691 mem_entry, LPORT_PROFILE_IDXf); 6692 } else { 6693 mem_idx = port; 6694 } 6695 MEM_LOCK(unit, mem); 6696 rv = soc_mem_read(unit, mem, MEM_BLOCK_ANY, mem_idx, &data); 6697 if (BCM_FAILURE(rv)) { 6698 LOG_ERROR(BSL_LS_BCM_TSN, 6699 (BSL_META_U(unit, "Failed to read mem[%s]"), 6700 SOC_MEM_NAME(unit, mem))); 6701 MEM_UNLOCK(unit, mem); 6702 return rv; 6703 } 6704 soc_mem_field32_set(unit, mem, &data, L2MCf, 6705 GH2_SR_AUTO_LEARN_GROUP_PORTS_L2MC_DEFAULT_VALUE); 6706 soc_mem_field32_set(unit, mem, &data, SR_MAC_PROXY_PROFILE_PTRf, 6707 GH2_SR_AUTO_LEARN_GROUP_PORTS_MACP_DEFAULT_VALUE); 6708 6709 rv = soc_mem_write(unit, mem, MEM_BLOCK_ALL, mem_idx, &data); 6710 if (BCM_FAILURE(rv)) { 6711 LOG_ERROR(BSL_LS_BCM_TSN, 6712 (BSL_META_U(unit, "Failed to write mem[%s]"), 6713 SOC_MEM_NAME(unit, mem))); 6714 MEM_UNLOCK(unit, mem); 6715 return rv; 6716 } 6717 MEM_UNLOCK(unit, mem); 6718 } 6719 } 6720 6721 GH2_TSN_FUNCTION_TRACE(unit, "OUT"); 6722 return BCM_E_NONE; 6723 } 6724 6725 /* 6726 * Function: 6727 * bcmi_gh2_tsn_sr_auto_learn_flow_id_ctrl_set 6728 * Purpose: 6729 * Set flow id control for auto learn subsystem 6730 * Parameters: 6731 * unit - (IN) Unit number 6732 * flow_type - (IN) SR Auto learn TX/RX flow type 6733 * current_fid - (IN) current flow element 6734 * last_fid - (IN) last flow element 6735 * id_size - (IN) total flow elements for auto learn 6736 * Returns: 6737 * BCM_E_XXX 6738 */ 6739 STATIC int 6740 bcmi_gh2_tsn_sr_auto_learn_flow_id_ctrl_set( 6741 int unit, 6742 bcmi_tsn_sr_auto_learn_flow_t flow_type, 6743 uint32 current_fid, 6744 uint32 last_fid, 6745 uint32 id_size) 6746 { 6747 uint64 rval64 = COMPILER_64_INIT(0, 0); 6748 soc_reg_t sr_flow_id_control_reg; 6749 6750 GH2_TSN_FUNCTION_TRACE(unit, "IN"); 6751 LOG_VERBOSE(BSL_LS_BCM_TSN, 6752 (BSL_META_U(unit, 6753 "current_fid %d, last_fid %d, id_size %d\n"), 6754 current_fid, last_fid, id_size)); 6755 6756 if (!soc_feature(unit, soc_feature_tsn_sr) || 6757 !soc_feature(unit, soc_feature_tsn_sr_auto_learn)) { 6758 return BCM_E_UNAVAIL; 6759 } 6760 6761 if (bcmi_sr_auto_learn_flow_tx == flow_type) { 6762 sr_flow_id_control_reg = SR_TX_FLOW_ID_CONTROLr; 6763 } else if (bcmi_sr_auto_learn_flow_rx == flow_type) { 6764 sr_flow_id_control_reg = SR_RX_FLOW_ID_CONTROLr; 6765 } else { 6766 return BCM_E_PARAM; 6767 } 6768 6769 BCM_IF_ERROR_RETURN( 6770 soc_reg64_get(unit, sr_flow_id_control_reg, REG_PORT_ANY, 0, &rval64)); 6771 soc_reg64_field32_set( 6772 unit, sr_flow_id_control_reg, &rval64, 6773 CURRENT_PTRf, current_fid); 6774 soc_reg64_field32_set( 6775 unit, sr_flow_id_control_reg, &rval64, 6776 LAST_PTRf, last_fid); 6777 soc_reg64_field32_set(unit, sr_flow_id_control_reg, &rval64, 6778 ID_SIZEf, id_size); 6779 BCM_IF_ERROR_RETURN( 6780 soc_reg64_set(unit, sr_flow_id_control_reg, REG_PORT_ANY, 0, rval64)); 6781 GH2_TSN_FUNCTION_TRACE(unit, "OUT"); 6782 return BCM_E_NONE; 6783 } 6784 6785 /* 6786 * Function: 6787 * bcmi_gh2_tsn_sr_auto_learn_flow_id_pool_get 6788 * Purpose: 6789 * Get flow id pool for auto learn subsystem 6790 * Parameters: 6791 * unit - (IN) Unit number 6792 * flow_type - (IN) SR Auto learn TX/RX flow type 6793 * prev_fid - (IN) previous HW flow ID 6794 * fid - (OUT) HW flow ID 6795 * Returns: 6796 * BCM_E_XXX 6797 */ 6798 STATIC int 6799 bcmi_gh2_tsn_sr_auto_learn_flow_id_pool_get( 6800 int unit, 6801 bcmi_tsn_sr_auto_learn_flow_t flow_type, 6802 uint32 prev_fid, 6803 uint32 *fid) 6804 { 6805 soc_mem_t mem = INVALIDm; 6806 soc_field_t field = NEXT_FLOW_IDf; 6807 sr_tx_flow_id_pool_entry_t tx_data; 6808 sr_rx_flow_id_pool_entry_t rx_data; 6809 void *data; 6810 uint32 hw_idx; 6811 int rx_flows, tx_flows; 6812 6813 GH2_TSN_FUNCTION_TRACE(unit, "IN"); 6814 if (!soc_feature(unit, soc_feature_tsn_sr) || 6815 !soc_feature(unit, soc_feature_tsn_sr_auto_learn)) { 6816 return BCM_E_UNAVAIL; 6817 } 6818 6819 /* Parameter validation */ 6820 if (NULL == fid) { 6821 return BCM_E_PARAM; 6822 } 6823 6824 /* Get fid from POOL.NEXT_FLOW_ID[prev_fid] */ 6825 hw_idx = (uint32)AUTO_LEARN_FLOW_ID_TO_HW_FLOW_ID(prev_fid); 6826 if (hw_idx >= soc_mem_index_count(unit, SR_SN_HISTORY_0m)) { 6827 return BCM_E_PARAM; 6828 } 6829 6830 BCM_IF_ERROR_RETURN( 6831 bcmi_gh2_tsn_sr_flows_get_num_flows(unit, &rx_flows, &tx_flows)); 6832 6833 if (bcmi_sr_auto_learn_flow_tx == flow_type) { 6834 mem = SR_TX_FLOW_ID_POOLm; 6835 sal_memset(&tx_data, 0, sizeof(sr_tx_flow_id_pool_entry_t)); 6836 data = (sr_tx_flow_id_pool_entry_t *)&tx_data; 6837 if (hw_idx >= tx_flows) { 6838 return BCM_E_PARAM; 6839 } 6840 } else if (bcmi_sr_auto_learn_flow_rx == flow_type) { 6841 mem = SR_RX_FLOW_ID_POOLm; 6842 sal_memset(&rx_data, 0, sizeof(sr_tx_flow_id_pool_entry_t)); 6843 data = (sr_rx_flow_id_pool_entry_t *)&rx_data; 6844 if (hw_idx >= rx_flows) { 6845 return BCM_E_PARAM; 6846 } 6847 } else { 6848 return BCM_E_PARAM; 6849 } 6850 6851 if (SOC_MEM_IS_VALID(unit, mem) || SOC_MEM_FIELD_VALID(unit, mem, field)) { 6852 BCM_IF_ERROR_RETURN( 6853 soc_mem_read(unit, mem, MEM_BLOCK_ANY, hw_idx, data)); 6854 soc_mem_field_get(unit, mem, 6855 data, field, fid); 6856 } else { 6857 return BCM_E_INTERNAL; 6858 } 6859 *fid = (uint32)AUTO_LEARN_HW_FLOW_ID_TO_FLOW_ID(flow_type, *fid); 6860 6861 LOG_VERBOSE(BSL_LS_BCM_TSN, 6862 (BSL_META_U(unit, 6863 "flow_type %d, prev_fid %d, *fid %d\n"), 6864 flow_type, prev_fid, *fid)); 6865 GH2_TSN_FUNCTION_TRACE(unit, "OUT"); 6866 return BCM_E_NONE; 6867 } 6868 6869 /* 6870 * Function: 6871 * bcmi_gh2_tsn_sr_auto_learn_flow_id_ctrl_get 6872 * Purpose: 6873 * get flow id control for auto learn subsystem 6874 * Parameters: 6875 * unit - (IN) Unit number 6876 * flow_type - (IN) SR Auto learn TX/RX flow type 6877 * current - (OUT) current flow element 6878 * last_fid - (OUT) last flow element 6879 * id_size - (OUT) total flow elements for auto learn 6880 * Returns: 6881 * BCM_E_XXX 6882 */ 6883 STATIC int 6884 bcmi_gh2_tsn_sr_auto_learn_flow_id_ctrl_get( 6885 int unit, 6886 bcmi_tsn_sr_auto_learn_flow_t flow_type, 6887 uint32 *current_fid, 6888 uint32 *last_fid, 6889 uint32 *id_size) 6890 { 6891 uint64 rval64 = COMPILER_64_INIT(0, 0); 6892 soc_reg_t sr_flow_id_control_reg; 6893 6894 GH2_TSN_FUNCTION_TRACE(unit, "IN"); 6895 6896 if (!soc_feature(unit, soc_feature_tsn_sr) || 6897 !soc_feature(unit, soc_feature_tsn_sr_auto_learn)) { 6898 return BCM_E_UNAVAIL; 6899 } 6900 6901 /* Parameter validation */ 6902 if (NULL == current_fid || 6903 NULL == last_fid || 6904 NULL == id_size) { 6905 return BCM_E_PARAM; 6906 } 6907 6908 if (bcmi_sr_auto_learn_flow_tx == flow_type) { 6909 sr_flow_id_control_reg = SR_TX_FLOW_ID_CONTROLr; 6910 } else if (bcmi_sr_auto_learn_flow_rx == flow_type) { 6911 sr_flow_id_control_reg = SR_RX_FLOW_ID_CONTROLr; 6912 } else { 6913 return BCM_E_PARAM; 6914 } 6915 6916 BCM_IF_ERROR_RETURN( 6917 soc_reg64_get(unit, sr_flow_id_control_reg, REG_PORT_ANY, 0, &rval64)); 6918 *current_fid = 6919 soc_reg64_field32_get(unit, sr_flow_id_control_reg, rval64, 6920 CURRENT_PTRf); 6921 *last_fid = 6922 soc_reg64_field32_get(unit, sr_flow_id_control_reg, rval64, 6923 LAST_PTRf); 6924 *id_size = 6925 soc_reg64_field32_get(unit, sr_flow_id_control_reg, rval64, 6926 ID_SIZEf); 6927 6928 LOG_VERBOSE(BSL_LS_BCM_TSN, 6929 (BSL_META_U(unit, 6930 "*current_fid %d, *last_fid %d, *id_size %d\n"), 6931 *current_fid, *last_fid, *id_size)); 6932 GH2_TSN_FUNCTION_TRACE(unit, "OUT"); 6933 return BCM_E_NONE; 6934 } 6935 6936 /* 6937 * Function: 6938 * bcmi_gh2_tsn_sr_auto_learn_flow_id_pool_set 6939 * Purpose: 6940 * Set flow id pool for auto learn subsystem 6941 * Parameters: 6942 * unit - (IN) Unit number 6943 * flow_type - (IN) SR Auto learn TX/RX flow type 6944 * prev_fid - (IN) previous HW flow ID 6945 * fid - (IN) HW flow ID 6946 * Returns: 6947 * BCM_E_XXX 6948 */ 6949 STATIC int 6950 bcmi_gh2_tsn_sr_auto_learn_flow_id_pool_set( 6951 int unit, 6952 bcmi_tsn_sr_auto_learn_flow_t flow_type, 6953 uint32 prev_fid, 6954 uint32 fid) 6955 { 6956 soc_mem_t mem = INVALIDm; 6957 soc_field_t field = NEXT_FLOW_IDf; 6958 sr_tx_flow_id_pool_entry_t tx_data; 6959 sr_rx_flow_id_pool_entry_t rx_data; 6960 void *data; 6961 uint32 hw_idx; 6962 uint32 next_fid; 6963 int rx_flows, tx_flows; 6964 6965 GH2_TSN_FUNCTION_TRACE(unit, "IN"); 6966 LOG_VERBOSE(BSL_LS_BCM_TSN, 6967 (BSL_META_U(unit, 6968 "flow_type %d, prev_fid %d, fid %d\n"), 6969 flow_type, prev_fid, fid)); 6970 6971 if (!soc_feature(unit, soc_feature_tsn_sr) || 6972 !soc_feature(unit, soc_feature_tsn_sr_auto_learn)) { 6973 return BCM_E_UNAVAIL; 6974 } 6975 6976 /* Covert it to next_fflow ID */ 6977 next_fid = (uint32)AUTO_LEARN_FLOW_ID_TO_HW_FLOW_ID(fid); 6978 6979 /* POOL.NEXT_FLOW_ID[prev_fid] = fid; */ 6980 hw_idx = (uint32)AUTO_LEARN_FLOW_ID_TO_HW_FLOW_ID(prev_fid); 6981 6982 BCM_IF_ERROR_RETURN( 6983 bcmi_gh2_tsn_sr_flows_get_num_flows(unit, &rx_flows, &tx_flows)); 6984 6985 if (bcmi_sr_auto_learn_flow_tx == flow_type) { 6986 mem = SR_TX_FLOW_ID_POOLm; 6987 sal_memset(&tx_data, 0, sizeof(sr_tx_flow_id_pool_entry_t)); 6988 data = (sr_tx_flow_id_pool_entry_t *)&tx_data; 6989 if (hw_idx >= tx_flows) { 6990 return BCM_E_PARAM; 6991 } 6992 } else if (bcmi_sr_auto_learn_flow_rx == flow_type) { 6993 mem = SR_RX_FLOW_ID_POOLm; 6994 sal_memset(&rx_data, 0, sizeof(sr_tx_flow_id_pool_entry_t)); 6995 data = (sr_rx_flow_id_pool_entry_t *)&rx_data; 6996 if (hw_idx >= rx_flows) { 6997 return BCM_E_PARAM; 6998 } 6999 } else { 7000 return BCM_E_PARAM; 7001 } 7002 7003 if (SOC_MEM_IS_VALID(unit, mem) && SOC_MEM_FIELD_VALID(unit, mem, field)) { 7004 BCM_IF_ERROR_RETURN( 7005 soc_mem_read(unit, mem, MEM_BLOCK_ANY, hw_idx, data)); 7006 soc_mem_field32_set(unit, mem, data, field, next_fid); 7007 BCM_IF_ERROR_RETURN( 7008 soc_mem_write(unit, mem, MEM_BLOCK_ALL, hw_idx, data)); 7009 } else { 7010 return BCM_E_INTERNAL; 7011 } 7012 GH2_TSN_FUNCTION_TRACE(unit, "OUT"); 7013 return BCM_E_NONE; 7014 } 7015 7016 /* 7017 * Function: 7018 * bcmi_gh2_tsn_sr_auto_learn_enable 7019 * Purpose: 7020 * Enable/disable SR flow auto learn subsystem 7021 * Parameters: 7022 * unit - (IN) Unit number 7023 * enable - (IN) Enable/disable auto learn 7024 * Returns: 7025 * BCM_E_XXX 7026 */ 7027 STATIC int 7028 bcmi_gh2_tsn_sr_auto_learn_enable( 7029 int unit, 7030 int enable) 7031 { 7032 uint32 rval = 0, val = 0; 7033 7034 GH2_TSN_FUNCTION_TRACE(unit, "IN"); 7035 LOG_VERBOSE(BSL_LS_BCM_TSN, 7036 (BSL_META_U(unit, 7037 "enable %d\n"), enable)); 7038 7039 if (!soc_feature(unit, soc_feature_tsn_sr) || 7040 !soc_feature(unit, soc_feature_tsn_sr_auto_learn)) { 7041 return BCM_E_UNAVAIL; 7042 } 7043 7044 BCM_IF_ERROR_RETURN(READ_HW_MAC_LEARNINGr(unit, &rval)); 7045 if (enable) { 7046 val = 1; 7047 } else { 7048 val = 0; 7049 } 7050 soc_reg_field_set(unit, 7051 HW_MAC_LEARNINGr, 7052 &rval, 7053 HW_MAC_LEARNING_ENABLEf, 7054 val); 7055 BCM_IF_ERROR_RETURN(WRITE_HW_MAC_LEARNINGr(unit, rval)); 7056 GH2_TSN_FUNCTION_TRACE(unit, "OUT"); 7057 return BCM_E_NONE; 7058 } 7059 7060 /* 7061 * Function: 7062 * bcmi_gh2_tsn_sr_auto_learn_enable_get 7063 * Purpose: 7064 * Get enable/disable status of SR flow auto learn subsystem 7065 * Parameters: 7066 * unit - (IN) Unit number 7067 * enabled - (OUT) enable/disable of SR flow auto learn 7068 * Returns: 7069 * BCM_E_XXX 7070 */ 7071 STATIC int 7072 bcmi_gh2_tsn_sr_auto_learn_enable_get( 7073 int unit, 7074 int *enabled) 7075 { 7076 uint32 rval = 0; 7077 7078 GH2_TSN_FUNCTION_TRACE(unit, "IN"); 7079 7080 if (!soc_feature(unit, soc_feature_tsn_sr) || 7081 !soc_feature(unit, soc_feature_tsn_sr_auto_learn)) { 7082 return BCM_E_UNAVAIL; 7083 } 7084 7085 /* Parameter validation */ 7086 if (NULL == enabled) { 7087 return BCM_E_PARAM; 7088 } 7089 7090 BCM_IF_ERROR_RETURN(READ_HW_MAC_LEARNINGr(unit, &rval)); 7091 *enabled = soc_reg_field_get(unit, 7092 HW_MAC_LEARNINGr, 7093 rval, 7094 HW_MAC_LEARNING_ENABLEf); 7095 LOG_VERBOSE(BSL_LS_BCM_TSN, 7096 (BSL_META_U(unit, 7097 "enabled %d\n"), *enabled)); 7098 7099 GH2_TSN_FUNCTION_TRACE(unit, "OUT"); 7100 return BCM_E_NONE; 7101 } 7102 #endif /* BCM_TSN_SR_SUPPORT */ 7103 7104 /* 7105 * Function: 7106 * bcmi_esw_tsn_stu_profile_encode 7107 * Purpose: 7108 * Encode the HW memory index and type 7109 * into profile id 7110 * Parameters: 7111 * unit - (IN) Unit number 7112 * index - (IN) HW memory index 7113 * type - (IN) Indicates ingress or egress stu profile 7114 * stu_profile_id - (OUT) profile id 7115 * Returns: 7116 * BCM_E_xxx 7117 */ 7118 STATIC int 7119 bcmi_gh2_tsn_stu_profile_encode( 7120 int unit, 7121 int index, 7122 bcm_tsn_stu_profile_type_t type, 7123 int *stu_profile_id) 7124 { 7125 soc_profile_mem_table_t *table; 7126 7127 /* The validity of the type is checked in the previous layer */ 7128 if (stu_profile_id == NULL) { 7129 return BCM_E_PARAM; 7130 } 7131 if (TSN_BKINFO(unit) != NULL) { 7132 TSN_STU_BKINFO_IS_INIT(unit, type); 7133 /* Check whether the memory index is valid */ 7134 STU_BKINFO_LOCK(unit); 7135 table = TSN_BKINFO(unit)->gh2_stu_bk_info.stu_profile[type]->tables; 7136 if (index > table->index_max || index < table->index_min) { 7137 STU_BKINFO_UNLOCK(unit); 7138 return BCM_E_PARAM; 7139 } 7140 STU_BKINFO_UNLOCK(unit); 7141 } 7142 if (type == bcmTsnStuProfileTypeIngress) { 7143 *stu_profile_id = index; 7144 } else { 7145 *stu_profile_id = index | EGR_MTU_STU_PROFILE_ID_ENCODE; 7146 } 7147 7148 return BCM_E_NONE; 7149 } 7150 7151 7152 /* 7153 * Function: 7154 * bcmi_gh2_tsn_stu_profile_traverse 7155 * Purpose: 7156 * Traverse the created match config. 7157 * Parameters: 7158 * unit - (IN) Unit number 7159 * cb - (IN) Traverse call back function 7160 * user_data - (IN) User data 7161 * Returns: 7162 * BCM_E_xxx 7163 */ 7164 STATIC int 7165 bcmi_gh2_tsn_stu_profile_traverse( 7166 int unit, 7167 bcm_tsn_stu_profile_traverse_cb cb, 7168 void *user_data) 7169 { 7170 int i, profile_id, rv; 7171 soc_profile_mem_table_t *table; 7172 bcm_tsn_stu_profile_type_t type; 7173 7174 if (user_data == NULL || cb == NULL) { 7175 return BCM_E_PARAM; 7176 } 7177 7178 /* Traverse on Profile Mem */ 7179 STU_BKINFO_LOCK(unit); 7180 for (type = bcmTsnStuProfileTypeIngress; type < bcmTsnStuProfileTypeCount; 7181 type++) { 7182 TSN_STU_BKINFO_IS_INIT(unit, type); 7183 table = TSN_BKINFO(unit)->gh2_stu_bk_info.stu_profile[type]->tables; 7184 7185 for (i = table->index_min; i <= table->index_max; i++) { 7186 bcmi_gh2_tsn_stu_profile_encode(unit, i, type, &profile_id); 7187 /* profile id 0 is the default value, won't traverse it */ 7188 if (table->entries[i].ref_count > 0 && i != 0) { 7189 rv = cb(unit, profile_id, user_data); 7190 if (BCM_FAILURE(rv)) { 7191 STU_BKINFO_UNLOCK(unit); 7192 return rv; 7193 } 7194 } 7195 } 7196 } 7197 STU_BKINFO_UNLOCK(unit); 7198 7199 return BCM_E_NONE; 7200 } 7201 7202 /* helper function to get the profile memory index */ 7203 STATIC int 7204 bcmi_gh2_tsn_stu_profile_mem_idx_get( 7205 int unit, 7206 bcm_tsn_stu_profile_type_t type, 7207 int *min, 7208 int *max) 7209 { 7210 if (min == NULL || max == NULL) { 7211 return BCM_E_PARAM; 7212 } 7213 if (type != bcmTsnStuProfileTypeIngress && 7214 type != bcmTsnStuProfileTypeEgress) { 7215 return BCM_E_PARAM; 7216 } 7217 *min = soc_mem_index_min(unit, gh2_stu_profile_mem[type]); 7218 *max = soc_mem_index_max(unit, gh2_stu_profile_mem[type]); 7219 7220 return BCM_E_NONE; 7221 } 7222 7223 /* 7224 * Function: 7225 * bcmi_gh2_tsn_stu_profile_mem_init 7226 * Purpose: 7227 * Initiate stu profile mem management structure 7228 * and set STU_PROFILEm entries to zero. 7229 * Parameters: 7230 * unit - (IN) Unit number 7231 * type - (IN) Indicates ingress or egress stu profile 7232 * Returns: 7233 * BCM_E_xxx 7234 */ 7235 STATIC int 7236 bcmi_gh2_tsn_stu_profile_mem_init( 7237 int unit, 7238 bcm_tsn_stu_profile_type_t type) 7239 { 7240 soc_mem_t mem; 7241 soc_mem_t mems[1]; 7242 int mem_words[1]; 7243 soc_profile_mem_t *pmem; 7244 int rv; 7245 7246 TSN_STU_BKINFO_IS_INIT(unit, type); 7247 7248 /* Set ingress STU profile memory HW table entries to zero */ 7249 #if defined(BCM_WARM_BOOT_SUPPORT) 7250 if (!SOC_WARM_BOOT(unit)) 7251 #endif /* BCM_WARM_BOOT_SUPPORT */ 7252 { 7253 SOC_IF_ERROR_RETURN 7254 (soc_mem_clear(unit, gh2_stu_profile_mem[type], MEM_BLOCK_ALL, 0)); 7255 } 7256 STU_BKINFO_LOCK(unit); 7257 pmem = TSN_BKINFO(unit)->gh2_stu_bk_info.stu_profile[type]; 7258 soc_profile_mem_t_init(pmem); 7259 mem = gh2_stu_profile_mem[type]; 7260 if (SOC_MEM_IS_VALID(unit, mem)) { 7261 mems[0] = mem; 7262 if (type == bcmTsnStuProfileTypeIngress) { 7263 mem_words[0] = BYTES2WORDS(sizeof(stu_profile_entry_t)); 7264 } else { 7265 mem_words[0] = BYTES2WORDS(sizeof(egr_stu_profile_entry_t)); 7266 } 7267 } else { 7268 STU_BKINFO_UNLOCK(unit); 7269 return BCM_E_INTERNAL; 7270 } 7271 rv = soc_profile_mem_create(unit, mems, mem_words, 1, pmem); 7272 7273 STU_BKINFO_UNLOCK(unit); 7274 return rv; 7275 } 7276 7277 /* 7278 * Function: 7279 * bcmi_gh2_tsn_stu_profile_create 7280 * Purpose: 7281 * Create stu profile with the config pointer 7282 * and return the assigned profile id. 7283 * Parameters: 7284 * unit - (IN) Unit number 7285 * type - (IN) Indicates ingress or egress stu profile 7286 * config - (IN) configuration of the stu profile 7287 * index - (OUT) HW index of ingress stu profile 7288 * Returns: 7289 * BCM_E_xxx 7290 */ 7291 STATIC int 7292 bcmi_gh2_tsn_stu_profile_create( 7293 int unit, 7294 bcm_tsn_stu_profile_type_t type, 7295 bcm_tsn_stu_config_t *config, 7296 uint32 *index) 7297 { 7298 void *entries[1]; 7299 soc_profile_mem_t *pmem; 7300 void *entry; 7301 stu_profile_entry_t entry_i; 7302 egr_stu_profile_entry_t entry_e; 7303 int rv; 7304 7305 if (index == NULL || config == NULL) { 7306 return BCM_E_PARAM; 7307 } 7308 TSN_STU_BKINFO_IS_INIT(unit, type); 7309 7310 if (type == bcmTsnStuProfileTypeIngress) { 7311 entry = &entry_i; 7312 } else { 7313 entry = &entry_e; 7314 } 7315 7316 SOC_IF_ERROR_RETURN 7317 (soc_mem_field32_fit(unit, gh2_stu_profile_mem[type], 7318 STU_SIZEf, config->size)); 7319 SOC_IF_ERROR_RETURN 7320 (soc_mem_field32_fit(unit, gh2_stu_profile_mem[type], 7321 STU_ERROR_ACTIONf, config->drop)); 7322 soc_mem_field32_set(unit, gh2_stu_profile_mem[type], (uint32 *)entry, 7323 STU_SIZEf, config->size); 7324 soc_mem_field32_set(unit, gh2_stu_profile_mem[type], (uint32 *)entry, 7325 STU_ERROR_ACTIONf, config->drop); 7326 STU_BKINFO_LOCK(unit); 7327 pmem = TSN_BKINFO(unit)->gh2_stu_bk_info.stu_profile[type]; 7328 entries[0] = entry; 7329 rv = soc_profile_mem_add(unit, pmem, entries, 1, index); 7330 STU_BKINFO_UNLOCK(unit); 7331 7332 return rv; 7333 } 7334 7335 /* 7336 * Function: 7337 * bcmi_gh2_tsn_stu_profile_get 7338 * Purpose: 7339 * Get stu profile configuration 7340 * with the profile id. 7341 * Parameters: 7342 * unit - (IN) Unit number 7343 * index - (IN) HW index of ingress stu profile 7344 * type - (IN) Indicates ingress or egress stu profile 7345 * config - (OUT) configuration of the stu profile 7346 * Returns: 7347 * BCM_E_xxx 7348 */ 7349 STATIC int 7350 bcmi_gh2_tsn_stu_profile_get( 7351 int unit, 7352 int index, 7353 bcm_tsn_stu_profile_type_t type, 7354 bcm_tsn_stu_config_t *config) 7355 { 7356 void *entries[1]; 7357 soc_profile_mem_t *pmem; 7358 void *entry; 7359 stu_profile_entry_t entry_i; 7360 egr_stu_profile_entry_t entry_e; 7361 7362 if (config == NULL) { 7363 return BCM_E_PARAM; 7364 } 7365 TSN_STU_BKINFO_IS_INIT(unit, type); 7366 7367 if (type == bcmTsnStuProfileTypeIngress) { 7368 entry = &entry_i; 7369 } else { 7370 entry = &entry_e; 7371 } 7372 STU_BKINFO_LOCK(unit); 7373 pmem = TSN_BKINFO(unit)->gh2_stu_bk_info.stu_profile[type]; 7374 entries[0] = entry; 7375 BCM_IF_ERROR_RETURN(soc_profile_mem_get(unit, pmem, index, 1, entries)); 7376 if (SOC_MEM_FIELD_VALID(unit, gh2_stu_profile_mem[type], STU_SIZEf) && 7377 SOC_MEM_FIELD_VALID(unit, gh2_stu_profile_mem[type], 7378 STU_ERROR_ACTIONf)) { 7379 config->size = 7380 soc_mem_field32_get(unit, gh2_stu_profile_mem[type], 7381 (uint32 *)entry, STU_SIZEf); 7382 config->drop = 7383 soc_mem_field32_get(unit, gh2_stu_profile_mem[type], 7384 (uint32 *)entry, STU_ERROR_ACTIONf); 7385 } else { 7386 STU_BKINFO_UNLOCK(unit); 7387 return BCM_E_INTERNAL; 7388 } 7389 STU_BKINFO_UNLOCK(unit); 7390 return BCM_E_NONE; 7391 } 7392 7393 /* 7394 * Function: 7395 * bcmi_gh2_tsn_ingress_stu_profile_set 7396 * Purpose: 7397 * Set stu profile with the profile id 7398 * and config parameter. 7399 * Parameters: 7400 * unit - (IN) Unit number 7401 * index - (IN) HW index of ingress stu profile 7402 * type - (IN) Indicates ingress or egress stu profile 7403 * config - (IN) configuration of the stu profile 7404 * Returns: 7405 * BCM_E_xxx 7406 */ 7407 STATIC int 7408 bcmi_gh2_tsn_stu_profile_set( 7409 int unit, 7410 int index, 7411 bcm_tsn_stu_profile_type_t type, 7412 bcm_tsn_stu_config_t *config) 7413 { 7414 int idx, profile_idx, rv; 7415 void *entries[1]; 7416 bcm_tsn_stu_config_t config_repl; 7417 soc_profile_mem_table_t *table; 7418 soc_profile_mem_t *pmem; 7419 void *entry; 7420 stu_profile_entry_t entry_i; 7421 egr_stu_profile_entry_t entry_e; 7422 7423 if (config == NULL) { 7424 return BCM_E_PARAM; 7425 } 7426 TSN_STU_BKINFO_IS_INIT(unit, type); 7427 7428 /* 7429 * Search for whether replicated profile mem config exist, 7430 * if existed return BCM_E_UNAVAIL 7431 */ 7432 bcm_tsn_stu_config_t_init(&config_repl); 7433 STU_BKINFO_LOCK(unit); 7434 table = TSN_BKINFO(unit)->gh2_stu_bk_info.stu_profile[type]->tables; 7435 for (idx = table->index_min; idx <= table->index_max; idx++) { 7436 bcmi_gh2_tsn_stu_profile_encode(unit, idx, type, &profile_idx); 7437 bcmi_gh2_tsn_stu_profile_get(unit, idx, type, &config_repl); 7438 if ((config_repl.size == config->size) && 7439 (config_repl.drop == config->drop)) { 7440 LOG_WARN(BSL_LS_BCMAPI_TSN, 7441 (BSL_META_U(unit, 7442 "config already existed, found" 7443 " stu profile id(%d)\n"), profile_idx)); 7444 STU_BKINFO_UNLOCK(unit); 7445 return BCM_E_EXISTS; 7446 } 7447 } 7448 STU_BKINFO_UNLOCK(unit); 7449 7450 SOC_IF_ERROR_RETURN 7451 (soc_mem_field32_fit(unit, gh2_stu_profile_mem[type], 7452 STU_SIZEf, config->size)); 7453 SOC_IF_ERROR_RETURN 7454 (soc_mem_field32_fit(unit, gh2_stu_profile_mem[type], STU_ERROR_ACTIONf, 7455 config->drop)); 7456 7457 if (type == bcmTsnStuProfileTypeIngress) { 7458 entry = &entry_i; 7459 } else { 7460 entry = &entry_e; 7461 } 7462 7463 if (SOC_MEM_FIELD_VALID(unit, gh2_stu_profile_mem[type], STU_SIZEf) && 7464 SOC_MEM_FIELD_VALID(unit, gh2_stu_profile_mem[type], 7465 STU_ERROR_ACTIONf)) { 7466 soc_mem_field32_set(unit, gh2_stu_profile_mem[type], 7467 entry, STU_SIZEf, config->size); 7468 soc_mem_field32_set(unit, gh2_stu_profile_mem[type], entry, 7469 STU_ERROR_ACTIONf, config->drop); 7470 } else { 7471 return BCM_E_INTERNAL; 7472 } 7473 STU_BKINFO_LOCK(unit); 7474 pmem = TSN_BKINFO(unit)->gh2_stu_bk_info.stu_profile[type]; 7475 entries[0] = entry; 7476 rv = soc_profile_mem_set(unit, pmem, entries, index); 7477 STU_BKINFO_UNLOCK(unit); 7478 7479 return rv; 7480 } 7481 7482 /* 7483 * Function: 7484 * bcmi_gh2_tsn_stu_profile_destroy 7485 * Purpose: 7486 * Clear the stu profile with the profile id 7487 * Parameters: 7488 * unit - (IN) Unit number 7489 * type - (IN) Indicates ingress or egress stu profile 7490 * index - (IN) Indicated the ingress stu profile entry 7491 * Returns: 7492 * BCM_E_xxx 7493 */ 7494 STATIC int 7495 bcmi_gh2_tsn_stu_profile_destroy( 7496 int unit, 7497 bcm_tsn_stu_profile_type_t type, 7498 int index) 7499 { 7500 uint32 buf; 7501 soc_profile_mem_t *pmem; 7502 void *entry; 7503 stu_profile_entry_t entry_i; 7504 egr_stu_profile_entry_t entry_e; 7505 int rv; 7506 7507 TSN_STU_BKINFO_IS_INIT(unit, type); 7508 if (type == bcmTsnStuProfileTypeIngress) { 7509 entry = &entry_i; 7510 } else { 7511 entry = &entry_e; 7512 } 7513 STU_BKINFO_LOCK(unit); 7514 pmem = TSN_BKINFO(unit)->gh2_stu_bk_info.stu_profile[type]; 7515 rv = soc_profile_mem_delete(unit, pmem, index); 7516 STU_BKINFO_UNLOCK(unit); 7517 BCM_IF_ERROR_RETURN(rv); 7518 7519 /* clear the HW table to zero */ 7520 buf = 0x00000000; 7521 SOC_IF_ERROR_RETURN(soc_mem_read(unit, gh2_stu_profile_mem[type], 7522 MEM_BLOCK_ANY, index, entry)); 7523 soc_mem_field_set(unit, gh2_stu_profile_mem[type], 7524 (uint32 *)entry, STU_SIZEf, &buf); 7525 soc_mem_field_set(unit, gh2_stu_profile_mem[type], (uint32 *)entry, 7526 STU_ERROR_ACTIONf, &buf); 7527 SOC_IF_ERROR_RETURN( 7528 soc_mem_write(unit, gh2_stu_profile_mem[type], MEM_BLOCK_ALL, 7529 index, entry)); 7530 7531 return BCM_E_NONE; 7532 } 7533 7534 /* 7535 * Function: 7536 * bcmi_gh2_tsn_ingress_stu_config_set 7537 * Purpose: 7538 * Set the priority of source ingress 7539 * stu profile index. 7540 * Parameters: 7541 * unit - (IN) Unit number 7542 * config - (IN) Configuration of the stu profile priority 7543 * Returns: 7544 * BCM_E_xxx 7545 */ 7546 STATIC int 7547 bcmi_gh2_tsn_ingress_stu_config_set( 7548 int unit, 7549 bcm_tsn_ingress_stu_config_t *config) 7550 { 7551 uint32 i, reg_val, val; 7552 int user_valid[bcmTsnStuSourceCount]; 7553 7554 if (config == NULL) { 7555 return BCM_E_PARAM; 7556 } 7557 /* source_order_count is mandatory to set as bcmTsnStuSourceCount */ 7558 if (config->source_order_count != bcmTsnStuSourceCount) { 7559 return BCM_E_PARAM; 7560 } 7561 for (i = 0; i < config->source_order_count; i++) { 7562 user_valid[i] = 0; 7563 } 7564 /* Check the user config is correct */ 7565 for (i = 0; i < config->source_order_count; i++) { 7566 switch (config->source_order[i]) { 7567 case bcmTsnStuSourceFieldLookup: 7568 user_valid[bcmTsnStuSourceFieldLookup]++; 7569 break; 7570 case bcmTsnStuSourcePort: 7571 user_valid[bcmTsnStuSourcePort]++; 7572 break; 7573 default: 7574 return BCM_E_PARAM; 7575 } 7576 } 7577 for (i = 0; i < config->source_order_count; i++) { 7578 if (user_valid[i] != 1) { 7579 return BCM_E_PARAM; 7580 } 7581 } 7582 /* 7583 * higher value in the register field means higher priority, and less 7584 * array index in the source_order means higher priority 7585 */ 7586 BCM_IF_ERROR_RETURN(READ_STU_PRIORITYr(unit, ®_val)); 7587 for (i = 0; i < config->source_order_count; i++) { 7588 val = bcmTsnStuSourceCount - 1 - i; 7589 switch (config->source_order[i]) { 7590 case bcmTsnStuSourceFieldLookup: 7591 soc_reg_field_set(unit, STU_PRIORITYr, ®_val, 7592 VFP_PRIORITYf, val); 7593 break; 7594 case bcmTsnStuSourcePort: 7595 soc_reg_field_set(unit, STU_PRIORITYr, ®_val, 7596 PORT_PRIORITYf, val); 7597 break; 7598 default: 7599 return BCM_E_PARAM; 7600 } 7601 } 7602 BCM_IF_ERROR_RETURN(WRITE_STU_PRIORITYr(unit, reg_val)); 7603 7604 return BCM_E_NONE; 7605 } 7606 7607 /* 7608 * Function: 7609 * bcmi_gh2_tsn_ingress_stu_config_get 7610 * Purpose: 7611 * Get the priority of source ingress 7612 * stu profile index. 7613 * Parameters: 7614 * unit - (IN) Unit number 7615 * config - (OUT) Configuration of the stu profile priority 7616 * Returns: 7617 * BCM_E_xxx 7618 */ 7619 STATIC int 7620 bcmi_gh2_tsn_ingress_stu_config_get( 7621 int unit, 7622 bcm_tsn_ingress_stu_config_t *config) 7623 { 7624 int i; 7625 uint32 reg_val, val; 7626 static const soc_field_t stu_pri_field[] = { 7627 VFP_PRIORITYf, PORT_PRIORITYf 7628 }; 7629 static const bcm_tsn_stu_source_t stu_src[] = { 7630 bcmTsnStuSourceFieldLookup, bcmTsnStuSourcePort 7631 }; 7632 7633 if (config == NULL) { 7634 return BCM_E_PARAM; 7635 } 7636 /* 7637 * higher value in the register field means higher priority, and less 7638 * array index in the source_order means higher priority 7639 */ 7640 config->source_order_count = bcmTsnStuSourceCount; 7641 BCM_IF_ERROR_RETURN(READ_STU_PRIORITYr(unit, ®_val)); 7642 for (i = 0; i < config->source_order_count; i++) { 7643 if (SOC_REG_FIELD_VALID(unit, STU_PRIORITYr, stu_pri_field[i])) { 7644 val = soc_reg_field_get(unit, STU_PRIORITYr, 7645 reg_val, stu_pri_field[i]); 7646 } else { 7647 return BCM_E_INTERNAL; 7648 } 7649 if (val < bcmTsnStuSourceCount) { 7650 config->source_order[(bcmTsnStuSourceCount - 1) - val] = 7651 stu_src[i]; 7652 } else { 7653 return BCM_E_INTERNAL; 7654 } 7655 } 7656 return BCM_E_NONE; 7657 } 7658 7659 /* Helper function to setup EGR_STU_CHECKm */ 7660 STATIC int 7661 bcmi_gh2_tsn_port_control_egress_stu_set( 7662 int unit, 7663 bcm_gport_t gport, 7664 bcm_tsn_pri_map_config_t *config) 7665 { 7666 bcm_port_t port; 7667 int pri, index, index_base, egr_prof_index; 7668 bcm_tsn_stu_profile_type_t type; 7669 egr_stu_check_entry_t egr_stu; 7670 7671 if (config == NULL) { 7672 return BCM_E_PARAM; 7673 } 7674 7675 if (config->map_type != bcmTsnPriMapTypeEgressStuProfile) { 7676 return BCM_E_PARAM; 7677 } 7678 7679 /* Validate and convert gport to local port */ 7680 BCM_IF_ERROR_RETURN( 7681 _bcm_esw_port_gport_validate(unit, gport, &port)); 7682 7683 if (port < 0 || port >= GH2_LOGIC_PORT_MAX_NUM) { 7684 return BCM_E_PARAM; 7685 } 7686 7687 index_base = port * EGRESS_MTU_STU_INT_PRI_NUM; 7688 sal_memset(&egr_stu, 0, sizeof(egr_stu)); 7689 for (pri = 0; pri < config->num_map_entries; pri++) { 7690 index = index_base + pri; 7691 SOC_IF_ERROR_RETURN( 7692 soc_mem_read(unit, EGR_STU_CHECKm, MEM_BLOCK_ANY, index, 7693 &egr_stu)); 7694 BCM_IF_ERROR_RETURN(bcmi_gh2_tsn_stu_profile_decode( 7695 unit, config->map_entries[pri].profile_id, 7696 &type, &egr_prof_index)); 7697 soc_mem_field32_set(unit, EGR_STU_CHECKm, &egr_stu, 7698 STU_PROFILE_INDEXf, egr_prof_index); 7699 SOC_IF_ERROR_RETURN( 7700 soc_mem_write(unit, EGR_STU_CHECKm, MEM_BLOCK_ALL, index, 7701 &egr_stu)); 7702 } 7703 7704 return BCM_E_NONE; 7705 } 7706 7707 /* Helper function to set PORT_TABm STU_PROFILE_INDEXf */ 7708 STATIC int 7709 bcmi_gh2_tsn_port_control_ingress_stu_set( 7710 int unit, 7711 bcm_gport_t gport, 7712 int index) 7713 { 7714 bcm_port_t port; 7715 sr_port_table_entry_t stu_profile; 7716 7717 /* Validate and convert gport to local port */ 7718 BCM_IF_ERROR_RETURN( 7719 _bcm_esw_port_gport_validate(unit, gport, &port)); 7720 7721 if (port < 0 || port >= GH2_LOGIC_PORT_MAX_NUM) { 7722 return BCM_E_PARAM; 7723 } 7724 /* check whether index is in the valid range */ 7725 SOC_IF_ERROR_RETURN( 7726 soc_mem_field32_fit(unit, SR_PORT_TABLEm, STU_PROFILE_INDEXf, index)); 7727 SOC_IF_ERROR_RETURN( 7728 soc_mem_read(unit, SR_PORT_TABLEm, MEM_BLOCK_ANY, port, 7729 &stu_profile)); 7730 soc_mem_field32_set(unit, SR_PORT_TABLEm, &stu_profile, 7731 STU_PROFILE_INDEXf, index); 7732 SOC_IF_ERROR_RETURN( 7733 soc_mem_write(unit, SR_PORT_TABLEm, MEM_BLOCK_ALL, port, 7734 &stu_profile)); 7735 7736 return BCM_E_NONE; 7737 } 7738 7739 /* Helper function to get PORT_TABm STU_PROFILE_INDEXf */ 7740 STATIC int 7741 bcmi_gh2_tsn_port_control_ingress_stu_get( 7742 int unit, 7743 bcm_gport_t gport, 7744 int *index) 7745 { 7746 bcm_port_t port; 7747 sr_port_table_entry_t stu_profile; 7748 7749 /* Validate and convert gport to local port */ 7750 BCM_IF_ERROR_RETURN( 7751 _bcm_esw_port_gport_validate(unit, gport, &port)); 7752 7753 if (port < 0 || port >= GH2_LOGIC_PORT_MAX_NUM || index == NULL) { 7754 return BCM_E_PARAM; 7755 } 7756 7757 SOC_IF_ERROR_RETURN( 7758 soc_mem_read(unit, SR_PORT_TABLEm, MEM_BLOCK_ANY, port, 7759 &stu_profile)); 7760 *index = soc_mem_field32_get(unit, SR_PORT_TABLEm, &stu_profile, 7761 STU_PROFILE_INDEXf); 7762 7763 return BCM_E_NONE; 7764 } 7765 7766 /* Free and clear the MTU bookkeeping info structure */ 7767 STATIC int 7768 bcmi_gh2_tsn_mtu_cleanup(int unit) 7769 { 7770 bcm_tsn_mtu_profile_type_t type; 7771 7772 TSN_BKINFO_IS_INIT(unit); 7773 for (type = bcmTsnMtuProfileTypeIngress; type < bcmTsnMtuProfileTypeCount; 7774 type++) { 7775 if (gh2_tsn_bkinfo[unit]->gh2_mtu_bk_info.mtu_profile[type] != NULL) { 7776 soc_profile_mem_destroy( 7777 unit, gh2_tsn_bkinfo[unit]->gh2_mtu_bk_info.mtu_profile[type]); 7778 TSN_FREE(unit, 7779 gh2_tsn_bkinfo[unit]->gh2_mtu_bk_info.mtu_profile[type], 7780 0); 7781 gh2_tsn_bkinfo[unit]->gh2_mtu_bk_info.mtu_profile[type] = NULL; 7782 } 7783 } 7784 if (gh2_tsn_bkinfo[unit]->gh2_mtu_bk_info.mutex != NULL) { 7785 sal_mutex_destroy(gh2_tsn_bkinfo[unit]->gh2_mtu_bk_info.mutex); 7786 gh2_tsn_bkinfo[unit]->gh2_mtu_bk_info.mutex = NULL; 7787 } 7788 7789 return BCM_E_NONE; 7790 } 7791 7792 /* Allocate MTU bookkeeping info resource */ 7793 STATIC int 7794 bcmi_gh2_tsn_mtu_init(int unit) 7795 { 7796 bcm_tsn_mtu_profile_type_t type; 7797 bcm_tsn_mtu_config_t config; 7798 uint32 idx; 7799 int rv; 7800 #if defined(BCM_WARM_BOOT_SUPPORT) 7801 int min, max, i; 7802 void *entry; 7803 mtu_profile_entry_t entry_i; 7804 egr_mtu_profile_entry_t entry_e; 7805 uint32 buff; 7806 soc_mem_t mem; 7807 soc_profile_mem_t *pmem; 7808 #endif /* BCM_WARM_BOOT_SUPPORT */ 7809 7810 /* 7811 * The mtu config is not used, but to occupy profile memory id 0 as invalid 7812 */ 7813 config.size = 0; 7814 config.drop = 0; 7815 7816 /* Create MTU mutex */ 7817 gh2_tsn_bkinfo[unit]->gh2_mtu_bk_info.mutex = 7818 sal_mutex_create("mtu_mutex"); 7819 if (gh2_tsn_bkinfo[unit]->gh2_mtu_bk_info.mutex == NULL) { 7820 bcmi_gh2_tsn_mtu_cleanup(unit); 7821 return BCM_E_MEMORY; 7822 } 7823 7824 for (type = bcmTsnMtuProfileTypeIngress; type < bcmTsnMtuProfileTypeCount; 7825 type++) { 7826 TSN_ALLOC( 7827 unit, gh2_tsn_bkinfo[unit]->gh2_mtu_bk_info.mtu_profile[type], 7828 soc_profile_mem_t, sizeof(soc_profile_mem_t), 7829 "GH2 TSN MTU Ingress bookkeeping info", 0, rv); 7830 if (BCM_FAILURE(rv)) { 7831 bcmi_gh2_tsn_mtu_cleanup(unit); 7832 return rv; 7833 } 7834 7835 /* Initialize and Create ingress mtu profile memory */ 7836 rv = bcmi_gh2_tsn_mtu_profile_mem_init(unit, type); 7837 if (BCM_FAILURE(rv)) { 7838 bcmi_gh2_tsn_mtu_cleanup(unit); 7839 return rv; 7840 } 7841 /* Profile memory id 0 as default/invalid */ 7842 rv = bcmi_gh2_tsn_mtu_profile_create(unit, type, &config, &idx); 7843 if (BCM_FAILURE(rv) || idx != 0) { 7844 bcmi_gh2_tsn_mtu_cleanup(unit); 7845 return rv; 7846 } 7847 #if defined(BCM_WARM_BOOT_SUPPORT) 7848 if (SOC_WARM_BOOT(unit)) { 7849 pmem = TSN_BKINFO(unit)->gh2_mtu_bk_info.mtu_profile[type]; 7850 mem = gh2_mtu_profile_mem[type]; 7851 7852 if (type == bcmTsnMtuProfileTypeIngress) { 7853 entry = &entry_i; 7854 } else { 7855 entry = &entry_e; 7856 } 7857 MTU_BKINFO_LOCK(unit); 7858 rv = bcmi_gh2_tsn_mtu_profile_mem_idx_get(unit, type, &min, &max); 7859 if (BCM_FAILURE(rv)) { 7860 MTU_BKINFO_UNLOCK(unit); 7861 return rv; 7862 } 7863 /* Recovering SW soc_profile_mem management */ 7864 for (i = min; i <= max; i++) { 7865 rv = soc_mem_read(unit, mem, MEM_BLOCK_ANY, i, entry); 7866 if (SOC_FAILURE(rv)) { 7867 MTU_BKINFO_UNLOCK(unit); 7868 return rv; 7869 } 7870 soc_mem_field_get(unit, mem, (uint32 *)entry, MTU_SIZEf, &buff); 7871 if (buff > 0) { 7872 rv = soc_profile_mem_reference(unit, pmem, i, 1); 7873 if (SOC_FAILURE(rv)) { 7874 MTU_BKINFO_UNLOCK(unit); 7875 return rv; 7876 } 7877 } 7878 } 7879 MTU_BKINFO_UNLOCK(unit); 7880 } 7881 #endif /* BCM_WARM_BOOT_SUPPORT */ 7882 } 7883 return BCM_E_NONE; 7884 } 7885 7886 /* Free and clear the STU bookkeeping info structure */ 7887 STATIC int 7888 bcmi_gh2_tsn_stu_cleanup(int unit) 7889 { 7890 bcm_tsn_stu_profile_type_t type; 7891 7892 TSN_BKINFO_IS_INIT(unit); 7893 for (type = bcmTsnStuProfileTypeIngress; type < bcmTsnStuProfileTypeCount; 7894 type++) { 7895 if (gh2_tsn_bkinfo[unit]->gh2_stu_bk_info.stu_profile[type] != NULL) { 7896 soc_profile_mem_destroy( 7897 unit, gh2_tsn_bkinfo[unit]->gh2_stu_bk_info.stu_profile[type]); 7898 TSN_FREE(unit, 7899 gh2_tsn_bkinfo[unit]->gh2_stu_bk_info.stu_profile[type], 7900 0); 7901 gh2_tsn_bkinfo[unit]->gh2_stu_bk_info.stu_profile[type] = NULL; 7902 } 7903 } 7904 if (gh2_tsn_bkinfo[unit]->gh2_stu_bk_info.mutex != NULL) { 7905 sal_mutex_destroy(gh2_tsn_bkinfo[unit]->gh2_stu_bk_info.mutex); 7906 gh2_tsn_bkinfo[unit]->gh2_stu_bk_info.mutex = NULL; 7907 } 7908 7909 return BCM_E_NONE; 7910 } 7911 7912 /* Allocate STU bookkeeping info resource */ 7913 STATIC int 7914 bcmi_gh2_tsn_stu_init(int unit) 7915 { 7916 bcm_tsn_stu_profile_type_t type; 7917 bcm_tsn_stu_config_t config; 7918 uint32 idx; 7919 int rv; 7920 #if defined(BCM_WARM_BOOT_SUPPORT) 7921 int min, max, i; 7922 void *entry; 7923 stu_profile_entry_t entry_i; 7924 egr_stu_profile_entry_t entry_e; 7925 uint32 buff; 7926 soc_mem_t mem; 7927 soc_profile_mem_t *pmem; 7928 #endif /*BCM_WARM_BOOT_SUPPORT*/ 7929 7930 7931 /* 7932 * The stu config is not used, but to occupy profile memory id 0 as invalid 7933 */ 7934 config.size = 0; 7935 config.drop = 0; 7936 7937 /* Create STU mutex */ 7938 gh2_tsn_bkinfo[unit]->gh2_stu_bk_info.mutex = 7939 sal_mutex_create("stu_mutex"); 7940 if (gh2_tsn_bkinfo[unit]->gh2_stu_bk_info.mutex == NULL) { 7941 bcmi_gh2_tsn_stu_cleanup(unit); 7942 return BCM_E_MEMORY; 7943 } 7944 7945 for (type = bcmTsnStuProfileTypeIngress; type < bcmTsnStuProfileTypeCount; 7946 type++) { 7947 TSN_ALLOC( 7948 unit, gh2_tsn_bkinfo[unit]->gh2_stu_bk_info.stu_profile[type], 7949 soc_profile_mem_t, sizeof(soc_profile_mem_t), 7950 "GH2 TSN STU Ingress bookkeeping info", 0, rv); 7951 if (BCM_FAILURE(rv)) { 7952 bcmi_gh2_tsn_stu_cleanup(unit); 7953 return rv; 7954 } 7955 7956 /* Initialize and Create ingress stu profile memory */ 7957 rv = bcmi_gh2_tsn_stu_profile_mem_init(unit, type); 7958 if (BCM_FAILURE(rv)) { 7959 bcmi_gh2_tsn_stu_cleanup(unit); 7960 return rv; 7961 } 7962 7963 /* Profile memory id 0 as default/invalid */ 7964 rv = bcmi_gh2_tsn_stu_profile_create(unit, type, &config, &idx); 7965 if (BCM_FAILURE(rv) || idx != 0) { 7966 bcmi_gh2_tsn_stu_cleanup(unit); 7967 return rv; 7968 } 7969 7970 #if defined(BCM_WARM_BOOT_SUPPORT) 7971 if (SOC_WARM_BOOT(unit)) { 7972 pmem = TSN_BKINFO(unit)->gh2_stu_bk_info.stu_profile[type]; 7973 mem = gh2_stu_profile_mem[type]; 7974 7975 if (type == bcmTsnStuProfileTypeIngress) { 7976 entry = &entry_i; 7977 } else { 7978 entry = &entry_e; 7979 } 7980 7981 STU_BKINFO_LOCK(unit); 7982 rv = bcmi_gh2_tsn_stu_profile_mem_idx_get(unit, type, &min, &max); 7983 if (BCM_FAILURE(rv)) { 7984 STU_BKINFO_UNLOCK(unit); 7985 return rv; 7986 } 7987 /* Recovering SW soc_profile_mem management */ 7988 for (i = min; i <= max; i++) { 7989 rv = soc_mem_read(unit, mem, MEM_BLOCK_ANY, i, entry); 7990 if (SOC_FAILURE(rv)) { 7991 STU_BKINFO_UNLOCK(unit); 7992 return rv; 7993 } 7994 soc_mem_field_get(unit, mem, (uint32 *)entry, STU_SIZEf, &buff); 7995 if (buff > 0) { 7996 rv = soc_profile_mem_reference(unit, pmem, i, 1); 7997 if (SOC_FAILURE(rv)) { 7998 STU_BKINFO_UNLOCK(unit); 7999 return rv; 8000 } 8001 } 8002 } 8003 STU_BKINFO_UNLOCK(unit); 8004 } 8005 #endif /* BCM_WARM_BOOT_SUPPORT */ 8006 } 8007 return BCM_E_NONE; 8008 } 8009 8010 #ifdef BCM_WARM_BOOT_SUPPORT 8011 /* 8012 * Function: 8013 * bcmi_gh2_tsn_egress_mtu_wb_reload 8014 * Purpose: 8015 * Reload the scache data into egr mtu sw data structure 8016 * Parameters: 8017 * unit - (IN) Unit number 8018 * idx - (IN) HW index 8019 * config - (OUT) pri_map_cofig 8020 * Returns: 8021 * BCM_E_xxx 8022 */ 8023 STATIC int 8024 bcmi_gh2_tsn_egress_mtu_wb_reload( 8025 int unit, 8026 int idx, 8027 bcm_tsn_pri_map_config_t *config) 8028 { 8029 int i, mem_idx, profile_id, mtu_idx; 8030 egr_mtu_check_entry_t egr_entry; 8031 8032 if (config == NULL) { 8033 return BCM_E_PARAM; 8034 } 8035 8036 if (idx < 0 || idx >= GH2_LOGIC_PORT_MAX_NUM) { 8037 return BCM_E_PARAM; 8038 } 8039 8040 /* Recovered the SW priority map data structure */ 8041 config->map_type = bcmTsnPriMapTypeEgressMtuProfile; 8042 config->num_map_entries = EGRESS_MTU_STU_INT_PRI_NUM; 8043 for (i = 0; i < config->num_map_entries; i++) { 8044 bcm_tsn_pri_map_entry_t_init(&config->map_entries[i]); 8045 config->map_entries[i].flags = BCM_TSN_PRI_MAP_ENTRY_PROFILE_ID; 8046 mem_idx = idx * EGRESS_MTU_STU_INT_PRI_NUM + i; 8047 SOC_IF_ERROR_RETURN 8048 (soc_mem_read(unit, EGR_MTU_CHECKm, MEM_BLOCK_ANY, mem_idx, 8049 &egr_entry)); 8050 if (SOC_MEM_FIELD_VALID(unit, EGR_MTU_CHECKm, 8051 MTU_PROFILE_INDEXf)) { 8052 mtu_idx = soc_mem_field32_get(unit, EGR_MTU_CHECKm, &egr_entry, 8053 MTU_PROFILE_INDEXf); 8054 } else { 8055 return BCM_E_INTERNAL; 8056 } 8057 bcmi_gh2_tsn_mtu_profile_encode( 8058 unit, mtu_idx, bcmTsnMtuProfileTypeEgress, &profile_id); 8059 config->map_entries[i].profile_id = profile_id; 8060 } 8061 return BCM_E_NONE; 8062 } 8063 8064 /* 8065 * Function: 8066 * bcmi_gh2_tsn_egress_stu_wb_reload 8067 * Purpose: 8068 * Reload the scache data into egr stu sw data structure 8069 * Parameters: 8070 * unit - (IN) Unit number 8071 * idx - (IN) HW index 8072 * config - (OUT) pri_map_cofig 8073 * Returns: 8074 * BCM_E_xxx 8075 */ 8076 STATIC int 8077 bcmi_gh2_tsn_egress_stu_wb_reload( 8078 int unit, 8079 int idx, 8080 bcm_tsn_pri_map_config_t *config) 8081 { 8082 int i, mem_idx, profile_id, stu_idx; 8083 egr_stu_check_entry_t egr_entry; 8084 8085 if (config == NULL) { 8086 return BCM_E_PARAM; 8087 } 8088 8089 if (idx < 0 || idx >= GH2_LOGIC_PORT_MAX_NUM) { 8090 return BCM_E_PARAM; 8091 } 8092 8093 /* Recovered the SW priority map data structure */ 8094 config->map_type = bcmTsnPriMapTypeEgressStuProfile; 8095 config->num_map_entries = EGRESS_MTU_STU_INT_PRI_NUM; 8096 for (i = 0; i < config->num_map_entries; i++) { 8097 bcm_tsn_pri_map_entry_t_init(&config->map_entries[i]); 8098 config->map_entries[i].flags = BCM_TSN_PRI_MAP_ENTRY_PROFILE_ID; 8099 mem_idx = idx * EGRESS_MTU_STU_INT_PRI_NUM + i; 8100 SOC_IF_ERROR_RETURN 8101 (soc_mem_read(unit, EGR_STU_CHECKm, MEM_BLOCK_ANY, mem_idx, 8102 &egr_entry)); 8103 if (SOC_MEM_FIELD_VALID(unit, EGR_STU_CHECKm, 8104 STU_PROFILE_INDEXf)) { 8105 stu_idx = soc_mem_field32_get(unit, EGR_STU_CHECKm, &egr_entry, 8106 STU_PROFILE_INDEXf); 8107 } else { 8108 return BCM_E_INTERNAL; 8109 } 8110 bcmi_gh2_tsn_stu_profile_encode( 8111 unit, stu_idx, bcmTsnStuProfileTypeEgress, &profile_id); 8112 config->map_entries[i].profile_id = profile_id; 8113 } 8114 return BCM_E_NONE; 8115 } 8116 8117 #endif /* BCM_WARM_BOOT_SUPPORT */ 8118 8119 #if defined(BCM_TSN_SR_SUPPORT) 8120 /* Per-chip SR MAC Proxy info */ 8121 STATIC const tsn_sr_mac_proxy_info_t gh2_sr_mac_proxy_info = { 8122 SR_MAC_PROXY_PROFILEm, /* soc_mem_t mem */ 8123 SR_PROXY_BITMAPf /* soc_field_t field */ 8124 }; 8125 8126 /* SR flow management platform specific data */ 8127 STATIC const bcmi_tsn_sr_flows_dev_info_t gh2_tsn_sr_flows_dev_info = { 8128 bcmi_gh2_tsn_sr_flows_get_num_flows, /* get_num_flows */ 8129 bcmi_gh2_tsn_sr_flows_get_hw_flow_id, /* get_hw_flow_id */ 8130 bcmi_gh2_tsn_sr_flows_get_sw_flow_idx, /* get_sw_flow_idx */ 8131 bcmi_gh2_tsn_sr_flows_check_rx_flow_config, /* check_rx_flow_config */ 8132 bcmi_gh2_tsn_sr_flows_check_tx_flow_config, /* check_tx_flow_config */ 8133 bcmi_gh2_tsn_sr_flows_clear_rx_flow, /* clear_rx_flow */ 8134 bcmi_gh2_tsn_sr_flows_clear_tx_flow, /* clear_tx_flow */ 8135 bcmi_gh2_tsn_sr_flows_write_rx_flow, /* write_rx_flow */ 8136 bcmi_gh2_tsn_sr_flows_write_tx_flow, /* write_tx_flow */ 8137 #ifdef BCM_WARM_BOOT_SUPPORT 8138 bcmi_gh2_tsn_sr_flows_read_rx_flow, /* read_rx_flow */ 8139 bcmi_gh2_tsn_sr_flows_read_tx_flow, /* read_tx_flow */ 8140 #endif /* BCM_WARM_BOOT_SUPPORT */ 8141 bcmi_gh2_tsn_sr_flows_get_rx_flow_status, /* get_rx_flow_status */ 8142 bcmi_gh2_tsn_sr_flows_get_tx_flow_status, /* get_tx_flow_status */ 8143 bcmi_gh2_tsn_sr_flows_reset_rx_flow, /* reset_rx_flow */ 8144 bcmi_gh2_tsn_sr_flows_seqnum_slice_alloc, /* seqnum_slice_alloc */ 8145 bcmi_gh2_tsn_sr_flows_seqnum_slice_free, /* seqnum_slice_free */ 8146 bcmi_gh2_tsn_sr_flows_seqnum_hist_read, /* seqnum_hist_read */ 8147 bcmi_gh2_tsn_sr_flows_seqnum_hist_write, /* seqnum_hist_write */ 8148 bcmi_gh2_tsn_sr_flows_seqnum_hist_reset, /* seqnum_hist_reset */ 8149 bcmi_gh2_tsn_sr_flows_clear_rx_flow_mtu, /* clear_rx_flow_mtu */ 8150 bcmi_gh2_tsn_sr_flows_clear_tx_flow_mtu /* clear_tx_flow_mtu */ 8151 }; 8152 8153 /* TSN-SR Port config set/get */ 8154 STATIC const tsn_sr_port_dev_info_t gh2_sr_port_dev_info = { 8155 #ifdef BCM_WARM_BOOT_SUPPORT 8156 bcmi_gh2_tsn_sr_port_prp_forwarding_sync, /* prp_forwarding_sync */ 8157 bcmi_gh2_tsn_sr_port_prp_forwarding_reload, /* prp_forwarding_reload */ 8158 #endif /* BCM_WARM_BOOT_SUPPORT */ 8159 bcmi_gh2_tsn_sr_port_config_set, /* sr_port_config_set */ 8160 bcmi_gh2_tsn_sr_port_config_get /* sr_port_config_get */ 8161 }; 8162 8163 #endif /* BCM_TSN_SR_SUPPORT */ 8164 8165 /* TSN event management structures */ 8166 /* device wrong lan interrupt register/field information */ 8167 typedef struct gh2_event_wrong_lan_info_s { 8168 bcm_tsn_event_type_t event_type; 8169 soc_field_t enable_status_field; 8170 soc_reg_t sts_reg; 8171 soc_field_t idx_field; 8172 soc_field_t mul_err_field; 8173 soc_field_t err_field; 8174 } gh2_event_wrong_lan_info_t; 8175 8176 STATIC const gh2_event_wrong_lan_info_t gh2_event_lan_err[] = { 8177 {bcmTsnEventTypeSrWrongLanA, 8178 IFP_WRONG_LAN_A_INTRf, 8179 IFP_WRONG_LAN_A_STATUS_INTRr, ENTRY_IDXf, MULTIPLE_WRONG_LAN_A_ERRf, 8180 WRONG_LAN_A_ERRf}, 8181 {bcmTsnEventTypeSrWrongLanB, 8182 IFP_WRONG_LAN_B_INTRf, 8183 IFP_WRONG_LAN_B_STATUS_INTRr, ENTRY_IDXf, MULTIPLE_WRONG_LAN_B_ERRf, 8184 WRONG_LAN_B_ERRf} 8185 }; 8186 8187 /* device counter threshold register/field information */ 8188 typedef struct gh2_event_cnt_threshold_s { 8189 soc_field_t sts_field; 8190 bcm_tsn_stat_t stat_type; 8191 bcm_tsn_stat_threshold_source_t th_src; 8192 } gh2_event_cnt_threshold_t; 8193 8194 /* Information from IP2_SR_TH_INTR_STATUSr */ 8195 STATIC const gh2_event_cnt_threshold_t gh2_event_cnt_thr_ip[] = { 8196 {SR_FLOW_INTR_RX_TAGGEDf, 8197 bcmTsnStatIngressSrTaggedPackets, bcmTsnStatThresholdSourceSRFlow}, 8198 {SR_FLOW_INTR_RXf, 8199 bcmTsnStatIngressNonLinkLocalPackets, bcmTsnStatThresholdSourceSRFlow}, 8200 {SR_FLOW_INTR_RX_WRONG_LANf, 8201 bcmTsnStatIngressSrWrongLanPackets, bcmTsnStatThresholdSourceSRFlow}, 8202 {SR_FLOW_INTR_RX_ERRORf, 8203 bcmTsnStatIngressSrRxErrorPackets, bcmTsnStatThresholdSourceSRFlow}, 8204 {SR_FLOW_INTR_RX_TAG_ERRORf, 8205 bcmTsnStatIngressSrTagErrorPackets, bcmTsnStatThresholdSourceSRFlow}, 8206 {SR_FLOW_INTR_RX_DUPLICATESf, 8207 bcmTsnStatIngressSrDuplicatePackets, bcmTsnStatThresholdSourceSRFlow}, 8208 {SR_FLOW_INTR_RX_OUTOFORDERf, 8209 bcmTsnStatIngressSrOutOfOrderSrPackets, bcmTsnStatThresholdSourceSRFlow}, 8210 {SR_FLOW_INTR_OWN_RXf, 8211 bcmTsnStatIngressSrOwnRxPackets, bcmTsnStatThresholdSourceSRFlow}, 8212 {SR_FLOW_INTR_UNEXPECTED_FRAMEf, 8213 bcmTsnStatIngressSrUnexpectedPackets, bcmTsnStatThresholdSourceSRFlow}, 8214 {SR_FLOW_INTR_MTU_ERRORf, 8215 bcmTsnStatIngressMtuErrorPackets, bcmTsnStatThresholdSourceSRFlow}, 8216 {SR_FLOW_INTR_STU_ERRORf, 8217 bcmTsnStatIngressStuErrorPackets, bcmTsnStatThresholdSourceSRFlow}, 8218 {SR_FLOW_INTR_RX_PASSEDf, 8219 bcmTsnStatIngressSrAcceptedSrPackets, bcmTsnStatThresholdSourceSRFlow}, 8220 {SR_FLOW_INTR_PROXY_MAC_ERRORf, 8221 bcmTsnStatIngressSrSaSrcFilteredPackets, bcmTsnStatThresholdSourceSRFlow}, 8222 {SR_PORT_INTR_RX_TAGGEDf, 8223 bcmTsnStatIngressSrTaggedPackets, bcmTsnStatThresholdSourcePort}, 8224 {SR_PORT_INTR_RXf, 8225 bcmTsnStatIngressNonLinkLocalPackets, bcmTsnStatThresholdSourcePort}, 8226 {SR_PORT_INTR_RX_WRONG_LANf, 8227 bcmTsnStatIngressSrWrongLanPackets, bcmTsnStatThresholdSourcePort}, 8228 {SR_PORT_INTR_RX_ERRORf, 8229 bcmTsnStatIngressSrRxErrorPackets, bcmTsnStatThresholdSourcePort}, 8230 {SR_PORT_INTR_RX_TAG_ERRORf, 8231 bcmTsnStatIngressSrTagErrorPackets, bcmTsnStatThresholdSourcePort}, 8232 {SR_PORT_INTR_RX_DUPLICATESf, 8233 bcmTsnStatIngressSrDuplicatePackets, bcmTsnStatThresholdSourcePort}, 8234 {SR_PORT_INTR_RX_OUTOFORDERf, 8235 bcmTsnStatIngressSrOutOfOrderSrPackets, bcmTsnStatThresholdSourcePort}, 8236 {SR_PORT_INTR_OWN_RXf, 8237 bcmTsnStatIngressSrOwnRxPackets, bcmTsnStatThresholdSourcePort}, 8238 {SR_PORT_INTR_UNEXPECTED_FRAMEf, 8239 bcmTsnStatIngressSrUnexpectedPackets, bcmTsnStatThresholdSourcePort}, 8240 {SR_PORT_INTR_MTU_ERRORf, 8241 bcmTsnStatIngressMtuErrorPackets, bcmTsnStatThresholdSourcePort}, 8242 {SR_PORT_INTR_STU_ERRORf, 8243 bcmTsnStatIngressStuErrorPackets, bcmTsnStatThresholdSourcePort}, 8244 {SR_PORT_INTR_RX_PASSEDf, 8245 bcmTsnStatIngressSrAcceptedSrPackets, bcmTsnStatThresholdSourcePort}, 8246 {SR_PORT_INTR_PROXY_MAC_ERRORf, 8247 bcmTsnStatIngressSrSaSrcFilteredPackets, bcmTsnStatThresholdSourcePort} 8248 }; 8249 8250 /* Information from EGR_MISC_INTR_STATUSr */ 8251 STATIC const gh2_event_cnt_threshold_t gh2_event_cnt_thr_ep[] = { 8252 {SR_FLOW_COUNT_THRESHOLD_TX_TAGGEDf, 8253 bcmTsnStatEgressSrTaggedPackets, bcmTsnStatThresholdSourceSRFlow}, 8254 {SR_FLOW_COUNT_THRESHOLD_TXf, 8255 bcmTsnStatEgressNonLinkLocalPackets, bcmTsnStatThresholdSourceSRFlow}, 8256 {SR_FLOW_THRESHOLD_TX_MTU_ERRORf, 8257 bcmTsnStatEgressMtuErrorPackets, bcmTsnStatThresholdSourceSRFlow}, 8258 {SR_FLOW_THRESHOLD_TX_STU_ERRORf, 8259 bcmTsnStatEgressStuErrorPackets, bcmTsnStatThresholdSourceSRFlow}, 8260 {SR_PORT_COUNT_THRESHOLD_TX_TAGGEDf, 8261 bcmTsnStatEgressSrTaggedPackets, bcmTsnStatThresholdSourcePort}, 8262 {SR_PORT_COUNT_THRESHOLD_TXf, 8263 bcmTsnStatEgressNonLinkLocalPackets, bcmTsnStatThresholdSourcePort}, 8264 {SR_PORT_THRESHOLD_TX_MTU_ERRORf, 8265 bcmTsnStatEgressMtuErrorPackets, bcmTsnStatThresholdSourcePort}, 8266 {SR_PORT_THRESHOLD_TX_STU_ERRORf, 8267 bcmTsnStatEgressStuErrorPackets, bcmTsnStatThresholdSourcePort} 8268 }; 8269 8270 STATIC int 8271 bcmi_gh2_tsn_event_mask(int unit, bcm_tsn_event_type_t event, uint32 enable) 8272 { 8273 uint64 val; 8274 8275 if (event == bcmTsnEventTypeSrWrongLanA) { 8276 BCM_IF_ERROR_RETURN(READ_IP2_INTR_ENABLEr(unit, &val)); 8277 soc_reg64_field32_set(unit, IP2_INTR_ENABLEr, &val, 8278 IFP_WRONG_LAN_A_INTRf, enable); 8279 BCM_IF_ERROR_RETURN(WRITE_IP2_INTR_ENABLEr(unit, val)); 8280 } 8281 if (event == bcmTsnEventTypeSrWrongLanB) { 8282 BCM_IF_ERROR_RETURN(READ_IP2_INTR_ENABLEr(unit, &val)); 8283 soc_reg64_field32_set(unit, IP2_INTR_ENABLEr, &val, 8284 IFP_WRONG_LAN_B_INTRf, enable); 8285 BCM_IF_ERROR_RETURN(WRITE_IP2_INTR_ENABLEr(unit, val)); 8286 } 8287 LOG_DEBUG(BSL_LS_BCM_TSN, 8288 (BSL_META("TSN EVT: event(%d) mask enable = %d\n"), 8289 event, enable)); 8290 return BCM_E_NONE; 8291 } 8292 8293 /* 8294 * Update the flow bitmap by specifying the event and hw flow id 8295 * when event == -1, update the active rx flow bitmap 8296 */ 8297 STATIC int 8298 bcmi_gh2_tsn_event_rx_flow_update( 8299 int unit, 8300 int event, 8301 int idx, 8302 int val) 8303 { 8304 int rv = BCM_E_NONE, fid, max; 8305 gh2_tsn_events_bkinfo_t *bkinfo = EVENTS_BKINFO(unit); 8306 8307 if (!soc_feature(unit, soc_feature_tsn_sr)) { 8308 return BCM_E_UNAVAIL; 8309 } 8310 EVENT_MGMT_LOCK(unit); 8311 if ((bcm_tsn_event_type_t)event == bcmTsnEventTypeSrWrongLanA) { 8312 if (val) { 8313 SHR_BITSET(bkinfo->wrong_lana_fbmp, idx); 8314 } else { 8315 SHR_BITCLR(bkinfo->wrong_lana_fbmp, idx); 8316 } 8317 } else if ((bcm_tsn_event_type_t)event == bcmTsnEventTypeSrWrongLanB) { 8318 if (val) { 8319 SHR_BITSET(bkinfo->wrong_lanb_fbmp, idx); 8320 } else { 8321 SHR_BITCLR(bkinfo->wrong_lanb_fbmp, idx); 8322 } 8323 } else if ((bcm_tsn_event_type_t)event == 8324 bcmTsnEventTypeSrSeqNumWindowAgeOut) { 8325 if (val) { 8326 SHR_BITSET(bkinfo->sn_reset_fbmp, idx); 8327 } else { 8328 SHR_BITCLR(bkinfo->sn_reset_fbmp, idx); 8329 } 8330 } else if (event == -1) { 8331 /* update the valid rx flow bmp */ 8332 if (val) { 8333 SHR_BITSET(bkinfo->active_rx_fbmp, idx); 8334 if (bkinfo->active_rx_fbmp_min == -1) { 8335 bkinfo->active_rx_fbmp_min = idx; 8336 bkinfo->active_rx_fbmp_max = idx; 8337 } 8338 if (idx < bkinfo->active_rx_fbmp_min) { 8339 bkinfo->active_rx_fbmp_min = idx; 8340 } 8341 if (idx > bkinfo->active_rx_fbmp_max) { 8342 bkinfo->active_rx_fbmp_max = idx; 8343 } 8344 } else { 8345 SHR_BITCLR(bkinfo->active_rx_fbmp, idx); 8346 if (SHR_BITNULL_RANGE(bkinfo->active_rx_fbmp, 0, 8347 bkinfo->max_rx_flows)) { 8348 /* active_rx_fbmp is empty */ 8349 bkinfo->active_rx_fbmp_min = bkinfo->active_rx_fbmp_max = -1; 8350 } else { 8351 if (idx == bkinfo->active_rx_fbmp_min) { 8352 /* need to get new min */ 8353 SHR_BIT_ITER(bkinfo->active_rx_fbmp, 8354 bkinfo->active_rx_fbmp_max, fid) { 8355 bkinfo->active_rx_fbmp_min = fid; 8356 break; 8357 } 8358 } 8359 if (idx == bkinfo->active_rx_fbmp_max) { 8360 max = bkinfo->active_rx_fbmp_max; 8361 /* need to get new max */ 8362 SHR_BIT_ITER(bkinfo->active_rx_fbmp, 8363 bkinfo->active_rx_fbmp_max, fid) { 8364 max = fid; 8365 } 8366 bkinfo->active_rx_fbmp_max = max; 8367 } 8368 } 8369 } 8370 } else { 8371 /* don't care the other types for GH2 */ 8372 rv = BCM_E_NONE; 8373 } 8374 EVENT_MGMT_UNLOCK(unit); 8375 return rv; 8376 } 8377 8378 STATIC int 8379 bcmi_gh2_tsn_event_flow_stat_get( 8380 int unit, 8381 bcm_tsn_event_type_t event, 8382 SHR_BITDCL *flowstate, 8383 SHR_BITDCL *filterflowstate, 8384 uint32 flow_number) 8385 { 8386 int min, max, rv, fidx, min_cd_val, cd_val; 8387 sr_rx_entry_t *rx_entries, *sr_rx; 8388 soc_mem_t mem; 8389 soc_field_t field, cd_field; 8390 int rx_flows, min_age_val, age_val; 8391 gh2_tsn_events_bkinfo_t *bkinfo = EVENTS_BKINFO(unit); 8392 8393 if ((bkinfo->active_rx_fbmp_min == -1) || 8394 (bkinfo->active_rx_fbmp_max == -1)) { 8395 LOG_ERROR(BSL_LS_BCM_TSN, 8396 (BSL_META_U(unit, "No active rx flow.\n"))); 8397 return BCM_E_INTERNAL; 8398 } 8399 if (flowstate != NULL && filterflowstate != NULL && 8400 (flow_number < bkinfo->max_rx_flows)) { 8401 return BCM_E_PARAM; 8402 } 8403 if ((filterflowstate == NULL) ^ (flowstate == NULL)) { 8404 return BCM_E_PARAM; 8405 } 8406 rx_flows = bkinfo->max_rx_flows; 8407 /* flowstate could be null when try to update the min count down value */ 8408 EVENT_MGMT_LOCK(unit); 8409 if (event == bcmTsnEventTypeSrWrongLanA) { 8410 field = WRONG_LAN_Af; 8411 cd_field = WRONG_LAN_A_AGE_OUT_COUNT_DOWNf; 8412 } else if (event == bcmTsnEventTypeSrWrongLanB) { 8413 field = WRONG_LAN_Bf; 8414 cd_field = WRONG_LAN_B_AGE_OUT_COUNT_DOWNf; 8415 } else if (event == bcmTsnEventTypeSrSeqNumWindowAgeOut) { 8416 field = AGE_OUT_INDICATORf; 8417 cd_field = SN_AGE_OUT_COUNT_DOWNf; 8418 } else { 8419 EVENT_MGMT_UNLOCK(unit); 8420 return BCM_E_PARAM; 8421 } 8422 8423 min = bkinfo->active_rx_fbmp_min; 8424 max = bkinfo->active_rx_fbmp_max; 8425 8426 rx_entries = soc_cm_salloc(unit, (max - min + 1) * sizeof(*rx_entries), 8427 "rx flow dma"); 8428 if (rx_entries == NULL) { 8429 EVENT_MGMT_UNLOCK(unit); 8430 return BCM_E_MEMORY; 8431 } 8432 mem = SR_RXm; 8433 rv = soc_mem_read_range(unit, mem, MEM_BLOCK_ANY, min, max, rx_entries); 8434 if (BCM_FAILURE(rv)) { 8435 soc_cm_sfree(unit, rx_entries); 8436 EVENT_MGMT_UNLOCK(unit); 8437 return rv; 8438 } 8439 min_cd_val = 0; 8440 min_age_val = 0; 8441 for (fidx = min; fidx <= max; fidx++) { 8442 sr_rx = soc_mem_table_idx_to_pointer(unit, mem, sr_rx_entry_t *, 8443 rx_entries, (fidx - min)); 8444 if (soc_mem_field32_get(unit, mem, sr_rx, field)) { 8445 if (flowstate != NULL) { 8446 SHR_BITSET(flowstate, fidx); 8447 } 8448 } 8449 age_val = soc_mem_field32_get(unit, mem, sr_rx, AGE_OUT_MULTIPLIERf); 8450 if (age_val) { 8451 if ((min_age_val == 0) || (age_val < min_age_val)) { 8452 min_age_val = age_val; 8453 } 8454 } 8455 cd_val = soc_mem_field32_get(unit, mem, sr_rx, cd_field); 8456 /* when count down value > age tick, assign count down value = 0 */ 8457 if (cd_val >= (1 << age_val)) { 8458 cd_val = 0; 8459 } 8460 if (cd_val) { 8461 if ((min_cd_val == 0) || (cd_val < min_cd_val)) { 8462 min_cd_val = cd_val; 8463 } 8464 } 8465 } 8466 soc_cm_sfree(unit, rx_entries); 8467 8468 if (min_cd_val > (1 << min_age_val)) { 8469 min_cd_val = (1 << min_age_val) - 1; 8470 } 8471 LOG_DEBUG(BSL_LS_BCM_TSN, 8472 (BSL_META_U(unit, "TSN EVT (%d): Min. count downtick %d\n"), 8473 event, min_cd_val)); 8474 8475 if (event == bcmTsnEventTypeSrWrongLanA) { 8476 bkinfo->wrong_lana_min_cd = min_cd_val; 8477 if (flowstate != NULL) { 8478 SHR_BITAND_RANGE(flowstate, bkinfo->wrong_lana_fbmp, 0, rx_flows, 8479 filterflowstate); 8480 } 8481 } else if (event == bcmTsnEventTypeSrWrongLanB) { 8482 bkinfo->wrong_lanb_min_cd = min_cd_val; 8483 if (flowstate != NULL) { 8484 SHR_BITAND_RANGE(flowstate, bkinfo->wrong_lanb_fbmp, 0, rx_flows, 8485 filterflowstate); 8486 } 8487 } else if (event == bcmTsnEventTypeSrSeqNumWindowAgeOut) { 8488 bkinfo->sn_reset_min_cd = min_cd_val; 8489 if (flowstate != NULL) { 8490 SHR_BITAND_RANGE(flowstate, bkinfo->sn_reset_fbmp, 0, rx_flows, 8491 filterflowstate); 8492 } 8493 } 8494 8495 EVENT_MGMT_UNLOCK(unit); 8496 return BCM_E_NONE; 8497 } 8498 8499 STATIC int 8500 bcmi_gh2_tsn_event_flow_stat_clear( 8501 int unit, 8502 bcm_tsn_event_type_t event, 8503 SHR_BITDCL *flowstate, 8504 uint32 flow_number) 8505 { 8506 gh2_tsn_events_bkinfo_t *bkinfo = EVENTS_BKINFO(unit); 8507 sr_rx_entry_t entry; 8508 soc_mem_t mem; 8509 soc_field_t field; 8510 int rx_flows, fidx, rv; 8511 8512 /* Parameter check */ 8513 if (flowstate == NULL) { 8514 return BCM_E_PARAM; 8515 } 8516 if (flow_number < bkinfo->max_rx_flows) { 8517 return BCM_E_PARAM; 8518 } 8519 8520 rx_flows = bkinfo->max_rx_flows; 8521 EVENT_MGMT_LOCK(unit); 8522 if (event == bcmTsnEventTypeSrWrongLanA) { 8523 field = WRONG_LAN_Af; 8524 } else if (event == bcmTsnEventTypeSrWrongLanB) { 8525 field = WRONG_LAN_Bf; 8526 } else if (event == bcmTsnEventTypeSrSeqNumWindowAgeOut) { 8527 field = AGE_OUT_INDICATORf; 8528 } else { 8529 EVENT_MGMT_UNLOCK(unit); 8530 return BCM_E_PARAM; 8531 } 8532 8533 mem = SR_RXm; 8534 MEM_LOCK(unit, mem); 8535 SHR_BIT_ITER(flowstate, rx_flows, fidx) { 8536 sal_memset(&entry, 0, sizeof(entry)); 8537 rv = soc_mem_read(unit, mem, MEM_BLOCK_ANY, fidx, &entry); 8538 if (BCM_FAILURE(rv)) { 8539 LOG_ERROR(BSL_LS_BCM_TSN, 8540 (BSL_META_U(unit, "Failed to read mem[%s]"), 8541 SOC_MEM_NAME(unit, mem))); 8542 MEM_UNLOCK(unit, mem); 8543 return rv; 8544 } 8545 soc_mem_field32_set(unit, mem, &entry, field, 0); 8546 rv = soc_mem_write(unit, mem, MEM_BLOCK_ALL, fidx, &entry); 8547 if (SOC_FAILURE(rv)) { 8548 LOG_ERROR(BSL_LS_BCM_TSN, 8549 (BSL_META_U(unit, "Failed to write mem[%s]"), 8550 SOC_MEM_NAME(unit, mem))); 8551 MEM_UNLOCK(unit, mem); 8552 return rv; 8553 } 8554 } 8555 MEM_UNLOCK(unit, mem); 8556 EVENT_MGMT_UNLOCK(unit); 8557 return BCM_E_NONE; 8558 } 8559 8560 STATIC int 8561 bcmi_gh2_tsn_event_poll(int unit) 8562 { 8563 gh2_tsn_events_bkinfo_t *bkinfo = EVENTS_BKINFO(unit); 8564 sal_usecs_t ctime; /* current time */ 8565 int diff, dtick = 0; 8566 8567 if (!soc_feature(unit, soc_feature_tsn_sr)) { 8568 /* Do nothing */ 8569 return BCM_E_NONE; 8570 } 8571 8572 if ((bkinfo->ageout_tick_ms == 0) || (bkinfo->age_enable == 0)) { 8573 return BCM_E_NONE; 8574 } 8575 8576 /* Check any active rx flow */ 8577 if ((bkinfo->active_rx_fbmp_min == -1) || 8578 (bkinfo->active_rx_fbmp_max == -1)) { 8579 /* Do nothing */ 8580 return BCM_E_NONE; 8581 } 8582 8583 EVENT_MGMT_LOCK(unit); 8584 8585 ctime = sal_time_usecs(); 8586 if (bkinfo->ptime != 0) { 8587 diff = SAL_USECS_SUB(ctime, bkinfo->ptime); 8588 bkinfo->ptime = ctime; 8589 dtick = diff / (bkinfo->ageout_tick_ms * MILLISECOND_USEC); 8590 } else { 8591 bkinfo->ptime = ctime; 8592 } 8593 8594 if ((bkinfo->wla_mask == 0) && (bkinfo->wla_tick == 0)) { 8595 /* 8596 * Get the updated min count down value 8597 * when interrupt mask is disabled and tick count down to 0. 8598 */ 8599 (void)bcmi_gh2_tsn_event_flow_stat_get( 8600 unit, bcmTsnEventTypeSrWrongLanA, NULL, NULL, 0); 8601 bkinfo->wla_tick = bkinfo->wrong_lana_min_cd; 8602 LOG_DEBUG(BSL_LS_BCM_TSN, 8603 (BSL_META_U(unit, "TSN EVT: WrongLanA tick %d\n"), 8604 bkinfo->wla_tick)); 8605 } 8606 bkinfo->wla_tick -= dtick; 8607 8608 if ((bkinfo->wlb_mask == 0) && (bkinfo->wlb_tick == 0)) { 8609 /* 8610 * Get the updated min count down value 8611 * when interrupt mask is disabled and tick count down to 0. 8612 */ 8613 (void)bcmi_gh2_tsn_event_flow_stat_get( 8614 unit, bcmTsnEventTypeSrWrongLanB, NULL, NULL, 0); 8615 bkinfo->wlb_tick = bkinfo->wrong_lanb_min_cd; 8616 LOG_DEBUG(BSL_LS_BCM_TSN, 8617 (BSL_META_U(unit, "TSN EVT: WrongLanB tick %d\n"), 8618 bkinfo->wlb_tick)); 8619 } 8620 bkinfo->wlb_tick -= dtick; 8621 8622 if (bkinfo->window_reset_mode == 8623 BCM_TSN_CONTROL_SR_SEQNUM_WINDOW_RESET_MODE_SW) { 8624 if (bkinfo->sn_reset_min_cd == 0) { 8625 /* Update sn_reset_min_cd */ 8626 (void)bcmi_gh2_tsn_event_flow_stat_get( 8627 unit, bcmTsnEventTypeSrSeqNumWindowAgeOut, NULL, NULL, 0); 8628 } 8629 if (bkinfo->sn_reset_min_cd > 0) { 8630 if (bkinfo->reset_tick == 0) { 8631 bkinfo->reset_tick = bkinfo->sn_reset_min_cd; 8632 LOG_DEBUG(BSL_LS_BCM_TSN, 8633 (BSL_META_U(unit, "TSN EVT: sn reset tick %d\n"), 8634 bkinfo->sn_reset_min_cd)); 8635 } 8636 bkinfo->reset_tick -= dtick; 8637 8638 /* notify callback to check the age-out indicator */ 8639 if (bkinfo->reset_tick <= 0) { 8640 if (bkinfo->gh2_flow_event_notify) { 8641 bkinfo->gh2_flow_event_notify( 8642 unit, bcmTsnEventTypeSrSeqNumWindowAgeOut, 1, 0); 8643 } 8644 bkinfo->reset_tick = 0; 8645 } 8646 } 8647 } 8648 if (!SHR_BITNULL_RANGE(bkinfo->wrong_lana_fbmp, 0, bkinfo->max_rx_flows)) { 8649 /* check the wrong LanA ageout ticks to enable the interrupt mask */ 8650 if (bkinfo->wla_tick <= 0) { 8651 if (bkinfo->wla_mask == 0) { 8652 (void)bcmi_gh2_tsn_event_mask(unit, 8653 bcmTsnEventTypeSrWrongLanA, 1); 8654 bkinfo->wla_mask = 1; 8655 } 8656 bkinfo->wla_tick = 0; 8657 } 8658 } 8659 if (!SHR_BITNULL_RANGE(bkinfo->wrong_lanb_fbmp, 0, bkinfo->max_rx_flows)) { 8660 /* check the wrong LanB ageout ticks to enable the interrupt mask */ 8661 if (bkinfo->wlb_tick <= 0) { 8662 if (bkinfo->wlb_mask == 0) { 8663 (void)bcmi_gh2_tsn_event_mask(unit, 8664 bcmTsnEventTypeSrWrongLanB, 1); 8665 bkinfo->wlb_mask = 1; 8666 } 8667 bkinfo->wlb_tick = 0; 8668 } 8669 } 8670 8671 EVENT_MGMT_UNLOCK(unit); 8672 8673 return BCM_E_NONE; 8674 } 8675 8676 STATIC int 8677 bcmi_gh2_tsn_flow_event_notify_register( 8678 int unit, 8679 bcmi_esw_tsn_flow_event_notify_cb cb) 8680 { 8681 gh2_tsn_events_bkinfo_t *bkinfo = EVENTS_BKINFO(unit); 8682 8683 bkinfo->gh2_flow_event_notify = cb; 8684 return BCM_E_NONE; 8685 } 8686 8687 STATIC int 8688 bcmi_gh2_tsn_cnt_excceed_notify_register( 8689 int unit, 8690 bcmi_esw_tsn_cnt_exceed_notify_cb cb) 8691 { 8692 gh2_tsn_events_bkinfo_t *bkinfo = EVENTS_BKINFO(unit); 8693 8694 bkinfo->gh2_cnt_exceed_notify = cb; 8695 return BCM_E_NONE; 8696 } 8697 8698 STATIC int 8699 bcmi_gh2_tsn_event_interrupt_handler( 8700 int unit, 8701 uint8 lan_err, 8702 uint8 ip_cnt_err, 8703 uint8 ep_cnt_err) 8704 { 8705 const gh2_event_wrong_lan_info_t *lan_err_info; 8706 const gh2_event_cnt_threshold_t *cnt_th_info; 8707 uint64 rval64, clear_field_64; 8708 uint32 rval32, multiple, clear_field; 8709 soc_reg_t sts_reg; 8710 bcmi_esw_tsn_flow_event_notify_cb fe_cb = NULL; 8711 bcmi_esw_tsn_cnt_exceed_notify_cb ce_cb = NULL; 8712 int idx, i; 8713 gh2_tsn_events_bkinfo_t *bkinfo = EVENTS_BKINFO(unit); 8714 8715 if (bkinfo->gh2_flow_event_notify) { 8716 fe_cb = bkinfo->gh2_flow_event_notify; 8717 } 8718 if (bkinfo->gh2_cnt_exceed_notify) { 8719 ce_cb = bkinfo->gh2_cnt_exceed_notify; 8720 } 8721 8722 if (ip_cnt_err) { 8723 multiple = 1; 8724 idx = -1; 8725 BCM_IF_ERROR_RETURN( 8726 soc_reg_get(unit, IP2_SR_TH_INTR_STATUSr, REG_PORT_ANY, 0, 8727 &rval64)); 8728 COMPILER_64_COPY(clear_field_64, rval64); 8729 8730 for (i = 0; i < COUNTOF(gh2_event_cnt_thr_ip); i++) { 8731 cnt_th_info = &gh2_event_cnt_thr_ip[i]; 8732 if (soc_reg64_field32_get(unit, IP2_SR_TH_INTR_STATUSr, rval64, 8733 cnt_th_info->sts_field)) { 8734 if (ce_cb) { 8735 (void)ce_cb(unit, cnt_th_info->stat_type, 8736 cnt_th_info->th_src, multiple, idx); 8737 } 8738 soc_reg64_field32_set(unit, IP2_SR_TH_INTR_STATUSr, 8739 &clear_field_64, 8740 cnt_th_info->sts_field, 0); 8741 } 8742 } 8743 /* Clear status */ 8744 BCM_IF_ERROR_RETURN( 8745 soc_reg_set(unit, IP2_SR_TH_INTR_STATUSr, REG_PORT_ANY, 0, 8746 clear_field_64)); 8747 } 8748 if (ep_cnt_err) { 8749 multiple = 1; 8750 idx = -1; 8751 BCM_IF_ERROR_RETURN(READ_EGR_MISC_INTR_STATUSr(unit, &rval32)); 8752 clear_field = rval32; 8753 for (i = 0; i < COUNTOF(gh2_event_cnt_thr_ep); i++) { 8754 cnt_th_info = &gh2_event_cnt_thr_ep[i]; 8755 if (soc_reg_field_get(unit, EGR_MISC_INTR_STATUSr, rval32, 8756 cnt_th_info->sts_field)) { 8757 if (ce_cb) { 8758 (void)ce_cb(unit, cnt_th_info->stat_type, 8759 cnt_th_info->th_src, multiple, idx); 8760 } 8761 soc_reg_field_set(unit, EGR_MISC_INTR_STATUSr, &clear_field, 8762 cnt_th_info->sts_field, 0); 8763 } 8764 } 8765 /* Clear status */ 8766 BCM_IF_ERROR_RETURN(WRITE_EGR_MISC_INTR_STATUSr(unit, clear_field)); 8767 } 8768 if (lan_err) { 8769 /* which lan error */ 8770 idx = -1; 8771 BCM_IF_ERROR_RETURN(READ_IP2_INTR_STATUSr(unit, &rval64)); 8772 for (i = 0; i < COUNTOF(gh2_event_lan_err); i++) { 8773 lan_err_info = &gh2_event_lan_err[i]; 8774 if (soc_reg64_field32_get(unit, IP2_INTR_STATUSr, rval64, 8775 lan_err_info->enable_status_field)) { 8776 sts_reg = lan_err_info->sts_reg; 8777 BCM_IF_ERROR_RETURN( 8778 soc_reg32_get(unit, sts_reg, 8779 REG_PORT_ANY, 0, &rval32)); 8780 if (soc_reg_field_get(unit, sts_reg, rval32, 8781 lan_err_info->err_field)) { 8782 multiple = soc_reg_field_get(unit, sts_reg, rval32, 8783 lan_err_info->mul_err_field); 8784 idx = soc_reg_field_get(unit, sts_reg, rval32, 8785 lan_err_info->idx_field); 8786 8787 if (fe_cb) { 8788 (void)fe_cb(unit, lan_err_info->event_type, 8789 multiple, idx); 8790 } 8791 /* 8792 * Disable the event mask to avoid 8793 * continuous wrong lan interrupt 8794 */ 8795 if (bkinfo->age_enable) { 8796 (void)bcmi_gh2_tsn_event_mask(unit, 8797 lan_err_info->event_type, 8798 0); 8799 if (lan_err_info->event_type == 8800 bcmTsnEventTypeSrWrongLanA) { 8801 bkinfo->wla_mask = 0; 8802 } 8803 if (lan_err_info->event_type == 8804 bcmTsnEventTypeSrWrongLanB) { 8805 bkinfo->wlb_mask = 0; 8806 } 8807 8808 } 8809 8810 /* Clear status */ 8811 BCM_IF_ERROR_RETURN( 8812 soc_reg32_set(unit, sts_reg, REG_PORT_ANY, 0, 0)); 8813 } 8814 } 8815 } 8816 } 8817 return BCM_E_NONE; 8818 } 8819 8820 /* Check if the device supports tsn event or not */ 8821 STATIC int 8822 bcmi_gh2_tsn_event_validate(int unit, bcmi_tsn_evt_inst_type_t inst_type) 8823 { 8824 switch (inst_type) { 8825 case bcmiTsnEvtCESys: 8826 case bcmiTsnEvtCEPort: 8827 return BCM_E_NONE; 8828 case bcmiTsnEvtCEFlow: 8829 case bcmiTsnEvtWLASys: 8830 case bcmiTsnEvtWLAFlow: 8831 case bcmiTsnEvtWLBSys: 8832 case bcmiTsnEvtWLBFlow: 8833 case bcmiTsnEvtSNSys: 8834 case bcmiTsnEvtSNFlow: 8835 if (!soc_feature(unit, soc_feature_tsn_sr)) { 8836 return BCM_E_UNAVAIL; 8837 } 8838 return BCM_E_NONE; 8839 default : 8840 return BCM_E_UNAVAIL; 8841 } 8842 } 8843 8844 STATIC int 8845 bcmi_gh2_tsn_event_mgmt_cleanup(int unit) 8846 { 8847 gh2_tsn_events_bkinfo_t *bkinfo = EVENTS_BKINFO(unit); 8848 8849 /* Free resource */ 8850 if (bkinfo->active_rx_fbmp != NULL) { 8851 sal_free(bkinfo->active_rx_fbmp); 8852 bkinfo->active_rx_fbmp = NULL; 8853 } 8854 if (bkinfo->wrong_lana_fbmp != NULL) { 8855 sal_free(bkinfo->wrong_lana_fbmp); 8856 bkinfo->wrong_lana_fbmp = NULL; 8857 } 8858 if (bkinfo->wrong_lanb_fbmp != NULL) { 8859 sal_free(bkinfo->wrong_lanb_fbmp); 8860 bkinfo->wrong_lanb_fbmp = NULL; 8861 } 8862 if (bkinfo->sn_reset_fbmp != NULL) { 8863 sal_free(bkinfo->sn_reset_fbmp); 8864 bkinfo->sn_reset_fbmp = NULL; 8865 } 8866 8867 if (bkinfo->event_mutex != NULL) { 8868 sal_mutex_destroy(bkinfo->event_mutex); 8869 bkinfo->event_mutex = NULL; 8870 } 8871 8872 /* Unregister event handler */ 8873 soc_gh2_tsn_event_handler_register(unit, NULL); 8874 8875 return BCM_E_NONE; 8876 } 8877 8878 STATIC int 8879 bcmi_gh2_tsn_event_mgmt_init(int unit) 8880 { 8881 #if defined(BCM_TSN_SR_SUPPORT) 8882 int rx_flows, tx_flows; 8883 #endif /* BCM_TSN_SR_SUPPORT */ 8884 gh2_tsn_events_bkinfo_t *bkinfo = EVENTS_BKINFO(unit); 8885 8886 sal_memset(bkinfo, 0, sizeof(gh2_tsn_events_bkinfo_t)); 8887 #if defined(BCM_TSN_SR_SUPPORT) 8888 /* Allocate resource */ 8889 if (soc_feature(unit, soc_feature_tsn_sr)) { 8890 /* Get # of flows and create the flow bmp */ 8891 BCM_IF_ERROR_RETURN( 8892 bcmi_gh2_tsn_sr_flows_get_num_flows(unit, &rx_flows, &tx_flows)); 8893 bkinfo->max_rx_flows = rx_flows; 8894 /* Allocate flows bitmap */ 8895 bkinfo->active_rx_fbmp = (SHR_BITDCL *) 8896 sal_alloc(SHR_BITALLOCSIZE(rx_flows), "gh2 event rx flow bmp"); 8897 if (bkinfo->active_rx_fbmp == NULL) { 8898 LOG_ERROR(BSL_LS_BCM_TSN, 8899 (BSL_META("EVENT: failed to allocate flow bmp\n"))); 8900 (void)bcmi_gh2_tsn_event_mgmt_cleanup(unit); 8901 return BCM_E_MEMORY; 8902 } 8903 sal_memset(bkinfo->active_rx_fbmp, 0, SHR_BITALLOCSIZE(rx_flows)); 8904 bkinfo->active_rx_fbmp_min = -1; 8905 bkinfo->active_rx_fbmp_max = -1; 8906 8907 bkinfo->wrong_lana_fbmp = (SHR_BITDCL *) 8908 sal_alloc(SHR_BITALLOCSIZE(rx_flows), 8909 "gh2 event wrong lan flow bmp"); 8910 if (bkinfo->wrong_lana_fbmp == NULL) { 8911 LOG_ERROR(BSL_LS_BCM_TSN, 8912 (BSL_META("EVENT: failed to allocate wrong lan fbmp\n"))); 8913 (void)bcmi_gh2_tsn_event_mgmt_cleanup(unit); 8914 return BCM_E_MEMORY; 8915 } 8916 sal_memset(bkinfo->wrong_lana_fbmp, 0, SHR_BITALLOCSIZE(rx_flows)); 8917 bkinfo->wrong_lanb_fbmp = (SHR_BITDCL *) 8918 sal_alloc(SHR_BITALLOCSIZE(rx_flows), 8919 "gh2 event wrong lan flow bmp"); 8920 if (bkinfo->wrong_lanb_fbmp == NULL) { 8921 LOG_ERROR(BSL_LS_BCM_TSN, 8922 (BSL_META("EVENT: failed to allocate wrong lan fbmp\n"))); 8923 (void)bcmi_gh2_tsn_event_mgmt_cleanup(unit); 8924 return BCM_E_MEMORY; 8925 } 8926 sal_memset(bkinfo->wrong_lanb_fbmp, 0, SHR_BITALLOCSIZE(rx_flows)); 8927 bkinfo->sn_reset_fbmp = (SHR_BITDCL *) 8928 sal_alloc(SHR_BITALLOCSIZE(rx_flows), 8929 "gh2 event sn reset flow bmp"); 8930 if (bkinfo->sn_reset_fbmp == NULL) { 8931 LOG_ERROR(BSL_LS_BCM_TSN, 8932 (BSL_META("EVENT: failed to allocate sn reset fbmp\n"))); 8933 (void)bcmi_gh2_tsn_event_mgmt_cleanup(unit); 8934 return BCM_E_MEMORY; 8935 } 8936 sal_memset(bkinfo->sn_reset_fbmp, 0, SHR_BITALLOCSIZE(rx_flows)); 8937 /* Get the inital value of the window reset mode */ 8938 (void)bcmi_gh2_tsn_control_get(unit, 8939 bcmTsnControlSrSeqNumWindowResetMode, 8940 &bkinfo->window_reset_mode); 8941 (void)bcmi_gh2_tsn_control_get(unit, bcmTsnControlSrAgeOutEnable, 8942 &bkinfo->age_enable); 8943 (void)bcmi_gh2_tsn_control_get(unit, bcmTsnControlSrAgeTickInterval, 8944 &bkinfo->ageout_tick_ms); 8945 } 8946 #endif 8947 8948 /* Create mutex for protecting event management */ 8949 bkinfo->event_mutex = sal_mutex_create("gh2 event mgmt"); 8950 if (NULL == bkinfo->event_mutex) { 8951 LOG_ERROR(BSL_LS_BCM_TSN, 8952 (BSL_META("EVENT: failed to create gh2 mgmt mutex\n"))); 8953 (void)bcmi_gh2_tsn_event_mgmt_cleanup(unit); 8954 return BCM_E_MEMORY; 8955 } 8956 8957 /* Register the event interrupt handler */ 8958 soc_gh2_tsn_event_handler_register(unit, 8959 bcmi_gh2_tsn_event_interrupt_handler); 8960 8961 return BCM_E_NONE; 8962 } 8963 8964 /* TSN event management platform specific data */ 8965 STATIC const bcmi_tsn_events_dev_info_t gh2_tsn_events_dev_info = { 8966 bcmi_gh2_tsn_flow_event_notify_register, /* register_flow_event_cb */ 8967 bcmi_gh2_tsn_cnt_excceed_notify_register, /* register_cnt_exceed_cb */ 8968 bcmi_gh2_tsn_event_validate, /* event validate */ 8969 bcmi_gh2_tsn_event_mask, /* Enable/disable event mask */ 8970 bcmi_gh2_tsn_event_rx_flow_update, /* update_rx_flow */ 8971 bcmi_gh2_tsn_event_flow_stat_get, /* Get the flow event state */ 8972 bcmi_gh2_tsn_event_flow_stat_clear, /* Clear the flow event state */ 8973 bcmi_gh2_tsn_event_poll /* poll function */ 8974 }; 8975 8976 /* MTU platform specific data */ 8977 STATIC const tsn_mtu_info_t gh2_mtu_ctrl_info = { 8978 /* per-chip control drivers */ 8979 #ifdef BCM_WARM_BOOT_SUPPORT 8980 bcmi_gh2_tsn_egress_mtu_wb_reload, 8981 #endif /* BCM_WARM_BOOT_SUPPORT */ 8982 GH2_LOGIC_PORT_MAX_NUM, 8983 bcmi_gh2_tsn_mtu_profile_mem_idx_get, 8984 bcmi_gh2_tsn_mtu_profile_create, 8985 bcmi_gh2_tsn_mtu_profile_set, 8986 bcmi_gh2_tsn_mtu_profile_get, 8987 bcmi_gh2_tsn_mtu_profile_destroy, 8988 bcmi_gh2_tsn_ingress_mtu_config_set, 8989 bcmi_gh2_tsn_ingress_mtu_config_get, 8990 bcmi_gh2_tsn_port_control_egress_mtu_set, 8991 bcmi_gh2_tsn_mtu_profile_decode, 8992 bcmi_gh2_tsn_mtu_profile_encode, 8993 bcmi_gh2_tsn_mtu_profile_traverse, 8994 bcmi_gh2_tsn_mtu_profmem_refcnt_get, 8995 bcmi_gh2_tsn_port_control_ingress_mtu_set, 8996 bcmi_gh2_tsn_port_control_ingress_mtu_get 8997 }; 8998 8999 /* STU platform specific data */ 9000 STATIC const tsn_stu_info_t gh2_stu_ctrl_info = { 9001 /* per-chip control drivers */ 9002 #ifdef BCM_WARM_BOOT_SUPPORT 9003 bcmi_gh2_tsn_egress_stu_wb_reload, 9004 #endif /* BCM_WARM_BOOT_SUPPORT */ 9005 GH2_LOGIC_PORT_MAX_NUM, 9006 bcmi_gh2_tsn_stu_profile_mem_idx_get, 9007 bcmi_gh2_tsn_stu_profile_create, 9008 bcmi_gh2_tsn_stu_profile_set, 9009 bcmi_gh2_tsn_stu_profile_get, 9010 bcmi_gh2_tsn_stu_profile_destroy, 9011 bcmi_gh2_tsn_ingress_stu_config_set, 9012 bcmi_gh2_tsn_ingress_stu_config_get, 9013 bcmi_gh2_tsn_port_control_egress_stu_set, 9014 bcmi_gh2_tsn_stu_profile_decode, 9015 bcmi_gh2_tsn_stu_profile_encode, 9016 bcmi_gh2_tsn_stu_profile_traverse, 9017 bcmi_gh2_tsn_stu_profmem_refcnt_get, 9018 bcmi_gh2_tsn_port_control_ingress_stu_set, 9019 bcmi_gh2_tsn_port_control_ingress_stu_get 9020 }; 9021 9022 /* TSN flow management platform specific data */ 9023 STATIC const bcmi_tsn_flows_dev_info_t gh2_tsn_flows_dev_info = { 9024 bcmi_gh2_tsn_flows_get_num_flows, /* get_num_flows */ 9025 bcmi_gh2_tsn_flows_get_hw_flow_id, /* get_hw_flow_id */ 9026 bcmi_gh2_tsn_flows_get_sw_flow_idx, /* get_sw_flow_idx */ 9027 bcmi_gh2_tsn_flows_check_flow_config, /* check_flow_config */ 9028 bcmi_gh2_tsn_flows_write_flow, /* write_flow */ 9029 #ifdef BCM_WARM_BOOT_SUPPORT 9030 bcmi_gh2_tsn_flows_read_flow, /* read_flow */ 9031 #endif /* BCM_WARM_BOOT_SUPPORT */ 9032 bcmi_gh2_tsn_flows_clear_flow, /* clear_flow */ 9033 bcmi_gh2_tsn_flows_clear_flow_mtu /* clear_flow_mtu */ 9034 }; 9035 9036 /* per-chip TSN Priority Map driver set */ 9037 STATIC const tsn_pri_map_info_t bcmi_gh2_tsn_pri_map_info = { 9038 "gh2_tsn_priority_map", /* table_name */ 9039 GH2_PRI_MAP_TSN_TAB_SIZE, /* table_size */ 9040 GH2_PRI_MAP_TSN_ENT_SIZE, /* entry_size */ 9041 bcmi_gh2_tsn_pri_map_tsn_set, /* tsn_pri_map_set */ 9042 bcmi_gh2_tsn_pri_map_tsn_get, /* tsn_pri_map_get */ 9043 bcmi_gh2_tsn_pri_map_tsn_delete, /* tsn_pri_map_delete */ 9044 bcmi_gh2_tsn_pri_map_tsn_hw_index_get, /* tsn_pri_map_hw_index_get */ 9045 bcmi_gh2_tsn_pri_map_tsn_sw_idx_get, /* tsn_pri_map_sw_idx_get */ 9046 bcmi_gh2_tsn_pri_map_tsn_wb_hw_existed /* tsn_pri_map_wb_hw_existed */ 9047 }; 9048 9049 #if defined(BCM_TSN_SR_SUPPORT) 9050 /* per-chip SR Priority Map driver set */ 9051 STATIC const tsn_pri_map_info_t bcmi_gh2_sr_pri_map_info = { 9052 "gh2_tsn_priority_map", /* table_name */ 9053 GH2_PRI_MAP_SR_TAB_SIZE, /* table_size */ 9054 GH2_PRI_MAP_SR_ENT_SIZE, /* entry_size */ 9055 bcmi_gh2_tsn_pri_map_sr_set, /* tsn_pri_map_set */ 9056 bcmi_gh2_tsn_pri_map_sr_get, /* tsn_pri_map_get */ 9057 bcmi_gh2_tsn_pri_map_sr_delete, /* tsn_pri_map_delete */ 9058 bcmi_gh2_tsn_pri_map_sr_hw_index_get, /* tsn_pri_map_hw_index_get */ 9059 bcmi_gh2_tsn_pri_map_sr_sw_idx_get, /* tsn_pri_map_sw_idx_get */ 9060 bcmi_gh2_tsn_pri_map_sr_wb_hw_existed /* tsn_pri_map_wb_hw_existed */ 9061 }; 9062 9063 /* Per-chip SR Auto Learn driver set */ 9064 STATIC const tsn_sr_auto_learn_info_t gh2_sr_auto_learn_info = { 9065 "gh2_tsn_sr_auto_learn_platform_info", /* table_name */ 9066 bcmi_gh2_tsn_sr_auto_learn_table_size_get, /* table_size */ 9067 { /* max_flow_num[bcmi_sr_auto_learn_flow_count] */ 9068 GH2_SR_AUTO_LEARN_TX_FLOW_SIZE, 9069 GH2_SR_AUTO_LEARN_RX_FLOW_SIZE 9070 }, 9071 bcmi_gh2_tsn_sr_auto_learn_group_port_set, /* group_port_set */ 9072 bcmi_gh2_tsn_sr_auto_learn_group_port_delete, /* group_port_delete */ 9073 bcmi_gh2_tsn_sr_auto_learn_group_port_reset_all, /* group_port_reset_all */ 9074 bcmi_gh2_tsn_sr_auto_learn_flow_id_ctrl_set, /* flow_id_ctrl_set */ 9075 bcmi_gh2_tsn_sr_auto_learn_flow_id_ctrl_get, /* flow_id_ctrl_get */ 9076 bcmi_gh2_tsn_sr_auto_learn_flow_id_pool_set, /* flow_id_pool_set */ 9077 bcmi_gh2_tsn_sr_auto_learn_flow_id_pool_get, /* flow_id_pool_get */ 9078 bcmi_gh2_tsn_sr_auto_learn_enable, /* enable */ 9079 bcmi_gh2_tsn_sr_auto_learn_enable_get /* enable_get */ 9080 }; 9081 #endif /* BCM_TSN_SR_SUPPORT */ 9082 9083 /* per-chip MTU Priority Map driver set */ 9084 STATIC const tsn_pri_map_info_t bcmi_gh2_mtu_pri_map_info = { 9085 "gh2_mtu_priority_map", /* table_name */ 9086 GH2_PRI_MAP_MTU_TAB_SIZE, /* table_size */ 9087 GH2_PRI_MAP_MTU_ENT_SIZE, /* entry_size */ 9088 NULL, /* tsn_pri_map_set */ 9089 NULL, /* tsn_pri_map_get */ 9090 NULL, /* tsn_pri_map_delete */ 9091 bcmi_gh2_tsn_pri_map_mtu_hw_index_get, /* tsn_pri_map_hw_index_get */ 9092 bcmi_gh2_tsn_pri_map_mtu_sw_idx_get, /* tsn_pri_map_sw_idx_get */ 9093 NULL /* tsn_pri_map_wb_hw_existed */ 9094 }; 9095 9096 /* per-chip STU Priority Map driver set */ 9097 STATIC const tsn_pri_map_info_t bcmi_gh2_stu_pri_map_info = { 9098 "gh2_stu_priority_map", /* table_name */ 9099 GH2_PRI_MAP_STU_TAB_SIZE, /* table_size */ 9100 GH2_PRI_MAP_STU_ENT_SIZE, /* entry_size */ 9101 NULL, /* tsn_pri_map_set */ 9102 NULL, /* tsn_pri_map_get */ 9103 NULL, /* tsn_pri_map_delete */ 9104 bcmi_gh2_tsn_pri_map_stu_hw_index_get, /* tsn_pri_map_hw_index_get */ 9105 bcmi_gh2_tsn_pri_map_stu_sw_idx_get, /* tsn_pri_map_sw_idx_get */ 9106 NULL /* tsn_pri_map_wb_hw_existed */ 9107 }; 9108 9109 /* Per-chip control driver set */ 9110 STATIC const tsn_chip_ctrl_info_t gh2_chip_ctrl_info = { 9111 /* per-chip control drivers */ 9112 bcmi_gh2_tsn_control_set, 9113 bcmi_gh2_tsn_control_get 9114 }; 9115 9116 /* GH2 TSN device info */ 9117 STATIC const bcmi_esw_tsn_dev_info_t gh2_tsn_devinfo = { 9118 #if defined(BCM_TSN_SR_SUPPORT) 9119 &gh2_sr_mac_proxy_info, 9120 &gh2_tsn_sr_flows_dev_info, 9121 &gh2_sr_port_dev_info, 9122 &gh2_sr_auto_learn_info, 9123 #endif /* BCM_TSN_SR_SUPPORT */ 9124 &gh2_tsn_flows_dev_info, 9125 9126 { /* tsn_pri_map_info[bcmTsnPriMapTypeCount] */ 9127 &bcmi_gh2_tsn_pri_map_info, 9128 #if defined(BCM_TSN_SR_SUPPORT) 9129 &bcmi_gh2_sr_pri_map_info, 9130 #else 9131 NULL, 9132 #endif 9133 &bcmi_gh2_mtu_pri_map_info, 9134 &bcmi_gh2_stu_pri_map_info, 9135 &bcmi_taf_gate_pri_map_info 9136 }, 9137 &gh2_mtu_ctrl_info, 9138 &gh2_stu_ctrl_info, 9139 &gh2_tsn_events_dev_info, 9140 &gh2_chip_ctrl_info 9141 }; 9142 9143 /* 9144 * Function: 9145 * bcmi_gh2_bkinfo_cleanup 9146 * Purpose: 9147 * Clear bookkeeping. 9148 * Parameters: 9149 * unit - (IN) unit number 9150 * init_error - (IN) 1 : init gh2_bkinfo failed so need cleanup 9151 * 0 : others 9152 * Returns: 9153 * BCM_E_XXX 9154 */ 9155 STATIC int 9156 bcmi_gh2_bkinfo_cleanup(int unit, int init_error) 9157 { 9158 (void)bcmi_gh2_tsn_event_mgmt_cleanup(unit); 9159 #if defined(BCM_TSN_SR_SUPPORT) 9160 if (soc_feature(unit, soc_feature_tsn_sr)) { 9161 /* SR flow management clean up */ 9162 SRFLOWS_BKINFO(unit).max_flows_rx = 0; 9163 SRFLOWS_BKINFO(unit).max_flows_tx = 0; 9164 (void)bcmi_gh2_tsn_sr_flows_seqnum_slices_cleanup(unit); 9165 (void)bcmi_gh2_tsn_sr_port_prp_forwarding_cleanup(unit, init_error); 9166 } 9167 #endif /* BCM_TSN_SR_SUPPORT */ 9168 9169 /* Free and clear the MTU & STU bookkeeping info structure */ 9170 if (soc_feature(unit, soc_feature_tsn_mtu_stu)) { 9171 (void)bcmi_gh2_tsn_mtu_cleanup(unit); 9172 (void)bcmi_gh2_tsn_stu_cleanup(unit); 9173 } 9174 9175 /* Free and clear the bookkeeping info structure */ 9176 if (gh2_tsn_bkinfo[unit] != NULL) { 9177 TSN_FREE(unit, gh2_tsn_bkinfo[unit], 0); 9178 gh2_tsn_bkinfo[unit] = NULL; 9179 } 9180 9181 return BCM_E_NONE; 9182 } 9183 9184 /* 9185 * Function: 9186 * bcmi_gh2_tsn_info_init 9187 * Description: 9188 * Setup the chip specific info. 9189 * Parameters: 9190 * unit - (IN) Unit number. 9191 * devinfo - (OUT) device info structure. 9192 * Returns: 9193 * BCM_E_XXX 9194 */ 9195 int 9196 bcmi_gh2_tsn_info_init( 9197 int unit, 9198 const bcmi_esw_tsn_dev_info_t **devinfo) 9199 { 9200 gh2_tsn_bkinfo_t *bkinfo = NULL; 9201 int rv = BCM_E_NONE; 9202 int i; 9203 9204 if (!SOC_UNIT_VALID(unit)) { 9205 return BCM_E_UNIT; 9206 } 9207 9208 if (devinfo == NULL) { 9209 return BCM_E_PARAM; 9210 } 9211 9212 /* GH2 TSN bookkeeping info initialization */ 9213 if (!gh2_tsn_bkinfo_initialized) { 9214 for (i = 0; i < BCM_MAX_NUM_UNITS; i++) { 9215 gh2_tsn_bkinfo[i] = NULL; 9216 } 9217 gh2_tsn_bkinfo_initialized = 1; 9218 } 9219 9220 /* Clean up the resource */ 9221 if (gh2_tsn_bkinfo[unit] != NULL) { 9222 rv = bcmi_gh2_bkinfo_cleanup(unit, 0); 9223 if (BCM_FAILURE(rv)) { 9224 return rv; 9225 } 9226 } 9227 9228 /* Allocate bookkeeping info resource */ 9229 /* coverity[bad_memset] */ 9230 TSN_ALLOC(unit, bkinfo, gh2_tsn_bkinfo_t, 9231 sizeof(gh2_tsn_bkinfo_t), 9232 "GH2 TSN bookkeeping info", 0, rv); 9233 if (BCM_FAILURE(rv)) { 9234 return rv; 9235 } 9236 gh2_tsn_bkinfo[unit] = bkinfo; 9237 9238 /* Allocate MTU & STU bookkeeping info resource */ 9239 if (soc_feature(unit, soc_feature_tsn_mtu_stu)) { 9240 rv = bcmi_gh2_tsn_mtu_init(unit); 9241 if (BCM_FAILURE(rv)) { 9242 (void)bcmi_gh2_bkinfo_cleanup(unit, 1); 9243 return rv; 9244 } 9245 9246 rv = bcmi_gh2_tsn_stu_init(unit); 9247 if (BCM_FAILURE(rv)) { 9248 (void)bcmi_gh2_bkinfo_cleanup(unit, 1); 9249 return rv; 9250 } 9251 } 9252 9253 #if defined(BCM_TSN_SR_SUPPORT) 9254 if (soc_feature(unit, soc_feature_tsn_sr)) { 9255 /* SR flow management - RX seqnum slice management initialization */ 9256 rv = bcmi_gh2_tsn_sr_flows_seqnum_slices_init(unit); 9257 if (BCM_FAILURE(rv)) { 9258 (void)bcmi_gh2_bkinfo_cleanup(unit, 1); 9259 return rv; 9260 } 9261 9262 /* SR PRP port forwarding initialization */ 9263 rv = bcmi_gh2_tsn_sr_port_prp_forwarding_init(unit); 9264 if (BCM_FAILURE(rv)) { 9265 (void)bcmi_gh2_bkinfo_cleanup(unit, 1); 9266 return rv; 9267 } 9268 } 9269 #endif /* BCM_TSN_SR_SUPPORT */ 9270 9271 rv = bcmi_gh2_tsn_event_mgmt_init(unit); 9272 if (BCM_FAILURE(rv)) { 9273 (void)bcmi_gh2_bkinfo_cleanup(unit, 1); 9274 return rv; 9275 } 9276 /* Return the chip info structure */ 9277 *devinfo = &gh2_tsn_devinfo; 9278 9279 return BCM_E_NONE; 9280 } 9281 9282 /* 9283 * Function: 9284 * bcmi_gh2_tsn_noninit_dev_info_get 9285 * Description: 9286 * Get the chip specific info without TSN module initialized. 9287 * Parameters: 9288 * unit - (IN) Unit number. 9289 * devinfo - (OUT) device info structure. 9290 * Returns: 9291 * BCM_E_XXX 9292 */ 9293 int 9294 bcmi_gh2_tsn_noninit_dev_info_get( 9295 int unit, 9296 const bcmi_esw_tsn_dev_info_t **devinfo) 9297 { 9298 if (devinfo == NULL) { 9299 return (BCM_E_PARAM); 9300 } 9301 9302 if (!SOC_UNIT_VALID(unit)) { 9303 return BCM_E_UNIT; 9304 } 9305 9306 /* Return the chip info structure */ 9307 *devinfo = &gh2_tsn_devinfo; 9308 9309 return BCM_E_NONE; 9310 } 9311 9312 /* 9313 * Function: 9314 * bcmi_gh2_tsn_info_detach 9315 * Description: 9316 * Detach the chip specific info. 9317 * Parameters: 9318 * unit - (IN) Unit number. 9319 * Returns: 9320 * BCM_E_XXX 9321 */ 9322 int 9323 bcmi_gh2_tsn_info_detach(int unit) 9324 { 9325 /* Detach bookkeeping info */ 9326 BCM_IF_ERROR_RETURN(bcmi_gh2_bkinfo_cleanup(unit, 0)); 9327 9328 return BCM_E_NONE; 9329 } 9330 9331 #endif /* BCM_GREYHOUND2_SUPPORT && BCM_TSN_SUPPORT */