tas.c (96275B)
1 /* 2 * 3 * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file. 4 * 5 * Copyright 2007-2019 Broadcom Inc. All rights reserved. 6 * 7 * File: tas.c 8 * Purpose: TAS driver 9 */ 10 11 #include <shared/bsl.h> 12 #include <soc/drv.h> 13 #include <bcm/cosq.h> 14 #include <bcm_int/esw/cosq.h> 15 #include <bcm_int/esw/tas.h> 16 #include <bcm_int/esw/port.h> 17 #include <bcm_int/esw_dispatch.h> 18 #if defined(INCLUDE_PTP) 19 #include <bcm_int/common/ptp.h> 20 #endif 21 #ifdef BCM_GREYHOUND2_SUPPORT 22 #include <bcm_int/esw/greyhound2.h> 23 #endif 24 #ifdef BCM_WARM_BOOT_SUPPORT 25 #include <soc/scache.h> 26 #include <bcm_int/esw/switch.h> 27 #endif /* BCM_WARM_BOOT_SUPPORT */ 28 29 #ifdef BCM_TAS_SUPPORT 30 /* 31 * Internal TAS profile control structure. 32 * To keep the software database from bcm api calls and corresponding 33 * remapped hardware data which should be programed to HW. 34 */ 35 typedef struct tas_profile_ctrl_s { 36 sal_mutex_t profile_mutex; 37 bcm_cosq_tas_profile_id_t pid; 38 bcm_cosq_tas_profile_state_t pstate; 39 bcm_port_t port; /* logical port */ 40 int hw_index; /* hw profile id */ 41 int num_user_entries; /* entries form API */ 42 bcm_cosq_tas_entry_t *user_entries; 43 int num_hw_entries; /* remapped HW entries */ 44 bcm_cosq_tas_entry_t *hw_entries; 45 bcm_ptp_timestamp_t base_time; 46 bcm_ptp_timestamp_t config_change_time; 47 uint32 cycle_time; 48 uint32 cycle_extension; 49 50 struct tas_profile_ctrl_s *next; /* For storing in a linked-list */ 51 } tas_profile_ctrl_t; 52 53 /* Mutex macro to protect tas_profile */ 54 #define TAS_PROFILE_LOCK(tp) \ 55 do {\ 56 if ((tp)->profile_mutex) { \ 57 sal_mutex_take((tp)->profile_mutex, sal_mutex_FOREVER); \ 58 }\ 59 } while (0) 60 #define TAS_PROFILE_UNLOCK(tp) \ 61 do {\ 62 if ((tp)->profile_mutex) { \ 63 sal_mutex_give((tp)->profile_mutex); \ 64 }\ 65 } while (0) 66 67 /* Define the maximum profile_cnt per profile list */ 68 #define MAX_TAS_PROFILE_CNT (10) 69 70 /* The soc properties which will be referenced for TAS profile entry remap */ 71 typedef struct tas_prop_info_s { 72 uint8 txoverrun; /* tas_calendar_auto_adjust_for_txoverrun */ 73 uint8 holdadvance; /* tas_calendar_auto_adjust_for_holdadvance */ 74 int maxsdu[BCM_COS_COUNT]; /* tas_calendar_auto_adjust_ref_maxsdu */ 75 } tas_prop_info_t; 76 77 /* 78 * Internal TAS control structure. 79 */ 80 typedef struct bcmi_esw_tas_control_s { 81 sal_mutex_t tas_mutex; 82 int profile_list_count; /* Max profile list count. */ 83 tas_profile_ctrl_t **profile_list; /* Profiles list. 84 * Two-dimension list, the first 85 * point to port, the second 86 * point to profile associated 87 * with the port. 88 */ 89 bcm_cosq_tas_profile_id_t *active_pid; /* Active profile id */ 90 bcm_cosq_tas_profile_id_t *process_pid; /* Process(commit or pending) 91 * profile id 92 */ 93 tas_prop_info_t *tas_properties; /* Port basis software cache 94 * of soc properties. 95 */ 96 /* device specific drivers */ 97 const tas_drv_t *tas_drvs; 98 } bcmi_esw_tas_control_t; 99 100 /* TAS control to keep unit-base tas information */ 101 STATIC bcmi_esw_tas_control_t *tas_control[SOC_MAX_NUM_DEVICES] = {NULL}; 102 103 /* Check if tas_control has been initialized. */ 104 #define TAS_IS_INIT(unit) \ 105 do { \ 106 if (tas_control[unit] == NULL) { \ 107 LOG_ERROR(BSL_LS_BCM_TAS, \ 108 (BSL_META_U(unit, \ 109 "TAS Error: Module not initialized\n"))); \ 110 return (BCM_E_INIT); \ 111 } \ 112 } while (0) 113 114 /* Mutex macro to protect tas_control[] */ 115 #define TAS_LOCK(tc) \ 116 sal_mutex_take((tc)->tas_mutex, sal_mutex_FOREVER) 117 #define TAS_UNLOCK(tc) \ 118 sal_mutex_give((tc)->tas_mutex) 119 120 /* 121 * Helper macro to insert the new profile (_inserted_ptr_) to 122 * tas_control[]->profile_list[_index_] 123 */ 124 #define TAS_PROFILE_INSERT(_profile_ptr_, _inserted_ptr_, _index_) \ 125 do { \ 126 (_inserted_ptr_)->next = (_profile_ptr_)[(_index_)]; \ 127 (_profile_ptr_)[(_index_)] = (_inserted_ptr_); \ 128 } while (0) 129 130 /* 131 * Helper macro to remove the profile (_removed_ptr_) from 132 * tas_control[]->profile_list[_index_] 133 */ 134 #define TAS_PROFILE_REMOVE(_profile_ptr_, _entry_type_, _removed_ptr_, _index_)\ 135 do { \ 136 _entry_type_ *_prev_ent_ = NULL; \ 137 _entry_type_ *_lkup_ent_ = (_profile_ptr_)[(_index_)]; \ 138 while (NULL != _lkup_ent_) { \ 139 if (_lkup_ent_ != (_removed_ptr_)) { \ 140 _prev_ent_ = _lkup_ent_; \ 141 _lkup_ent_ = _lkup_ent_->next; \ 142 continue; \ 143 } \ 144 if (_prev_ent_ != NULL) { \ 145 _prev_ent_->next = (_removed_ptr_)->next; \ 146 } else { \ 147 (_profile_ptr_)[(_index_)] = (_removed_ptr_)->next; \ 148 } \ 149 break; \ 150 } \ 151 } while (0) 152 153 /* 154 * Helper macro to remove all the profiles from 155 * tas_control[]->profile_list[_index_] 156 */ 157 #define TAS_PROFILE_REMOVE_ALL(_profile_ptr_, _entry_type_, _index_) \ 158 do { \ 159 _entry_type_ *_node_ = NULL; \ 160 _entry_type_ *_head_ = (_profile_ptr_)[(_index_)]; \ 161 while (NULL != _head_) { \ 162 _node_ = _head_; \ 163 _head_ = _head_->next; \ 164 sal_free(_node_); \ 165 _node_ = NULL; \ 166 } \ 167 } while (0) 168 169 /* 170 * Helper macro to iterate the profile entry from 171 * tas_control[]->profile_list[_index_] 172 */ 173 #define TAS_PROFILE_ITER(_profile_ptr_, _entry_ptr_, _index_) \ 174 for ((_entry_ptr_) = (_profile_ptr_)[(_index_)]; (_entry_ptr_) != NULL; \ 175 (_entry_ptr_) = (_entry_ptr_)->next) 176 177 /* String corresponding to the enum in bcm_cosq_tas_profile_state_t */ 178 static const char *pstate_string[] = 179 { 180 "Init", 181 "Committed", 182 "Pending", 183 "Active", 184 "Expired", 185 "Error" 186 }; 187 188 /* Composition of tas profile id */ 189 /* 190 * port : max 8 bits (support 256 ports) 191 * idx : max 16 bits (0~65535) 192 */ 193 #define TAS_PID_PORT_START_BIT 24 194 #define TAS_PID_PORT_END_BIT 31 195 #define TAS_PID_IDX_START_BIT 0 196 #define TAS_PID_IDX_END_BIT 15 197 198 #define TAS_PID_PORT_MASK \ 199 ((1 << (TAS_PID_PORT_END_BIT - TAS_PID_PORT_START_BIT + 1)) - 1) 200 #define TAS_PID_IDX_MASK \ 201 ((1 << (TAS_PID_IDX_END_BIT - TAS_PID_IDX_START_BIT + 1)) - 1) 202 203 /* 204 * Function: 205 * tas_control_get 206 * Purpose: 207 * Get the tas_control[unit] pointer 208 * Parameters: 209 * unit - (IN) unit number 210 * tc - (OUT) pointer to tas_control[unit] 211 * Returns: 212 * BCM_E_XXX 213 */ 214 STATIC int 215 tas_control_get(int unit, bcmi_esw_tas_control_t **tc) 216 { 217 /* Input parameters check. */ 218 if (NULL == tc) { 219 return (BCM_E_PARAM); 220 } 221 /* Make sure system was initialized. */ 222 TAS_IS_INIT(unit); 223 224 /* Fill tas control structure. */ 225 *tc = tas_control[unit]; 226 227 return (BCM_E_NONE); 228 } 229 230 /* 231 * Function: 232 * tas_profile_ctrl_get 233 * Purpose: 234 * Get the internal profile information by specifying profile id 235 * Parameters: 236 * unit - (IN) unit number 237 * pid - (IN) unit number 238 * profile_p - (IN) pointer to internal profile 239 * Returns: 240 * BCM_E_XXX 241 */ 242 STATIC int 243 tas_profile_ctrl_get( 244 int unit, 245 bcm_cosq_tas_profile_id_t pid, 246 tas_profile_ctrl_t **profile_p) 247 { 248 bcmi_esw_tas_control_t *tc; 249 tas_profile_ctrl_t *tp; 250 bcm_port_t lport; 251 252 if (NULL == profile_p) { 253 return (BCM_E_PARAM); 254 } 255 /* Get unit TAS control structure. */ 256 BCM_IF_ERROR_RETURN(tas_control_get(unit, &tc)); 257 258 lport = (pid >> TAS_PID_PORT_START_BIT) & TAS_PID_PORT_MASK; 259 TAS_LOCK(tc); 260 /* Iterate over the profiles linked-list looking for a matching id */ 261 tp = tc->profile_list[lport]; 262 while (tp != NULL) { 263 if (tp->pid == pid) { 264 *profile_p = tp; 265 TAS_UNLOCK(tc); 266 return (BCM_E_NONE); 267 } 268 tp = tp->next; 269 } 270 TAS_UNLOCK(tc); 271 return (BCM_E_NOT_FOUND); 272 } 273 274 /* 275 * Function: 276 * tas_gport_validate 277 * Purpose: 278 * gport parameter check and get the corresponding lport 279 * Parameters: 280 * unit - (IN) unit number 281 * gport - (IN) gport 282 * local_port - (OUT) logical port 283 * Returns: 284 * BCM_E_XXX 285 */ 286 STATIC int 287 tas_gport_validate(int unit, bcm_gport_t gport, bcm_port_t *local_port) 288 { 289 BCM_IF_ERROR_RETURN(_bcm_esw_port_gport_validate(unit, gport, local_port)); 290 if (!BCM_PBMP_MEMBER(PBMP_PORT_ALL(unit), *local_port)) { 291 return BCM_E_PORT; 292 } 293 return BCM_E_NONE; 294 } 295 296 /* Software cache to keep the soc propery for TAS profile entry remap */ 297 STATIC int 298 bcmi_esw_tas_property_cache_init(int unit) 299 { 300 bcmi_esw_tas_control_t *tc = NULL; 301 int rv = BCM_E_NONE; 302 int p, c; 303 #ifndef NDEBUG 304 int len; 305 #endif /* !NDEBUG */ 306 char *str, *p_str; 307 tas_prop_info_t *tas_prop; 308 char prop[SOC_PROPERTY_NAME_MAX]; 309 int default_sdu = 0; 310 311 BCM_IF_ERROR_RETURN(tas_control_get(unit, &tc)); 312 313 TAS_LOCK(tc); 314 /* Use the max index to keep w/o suffix value */ 315 tas_prop = &tc->tas_properties[tc->profile_list_count]; 316 tas_prop->txoverrun = 317 soc_property_get(unit, spn_TAS_CALENDAR_AUTO_ADJUST_FOR_TXOVERRUN, 0); 318 tas_prop->holdadvance = 319 soc_property_get(unit, spn_TAS_CALENDAR_AUTO_ADJUST_FOR_HOLDADVANCE, 0); 320 /* Get the default maxsdu size */ 321 default_sdu = 322 soc_property_get(unit, spn_TAS_CALENDAR_AUTO_ADJUST_REF_MAXSDU, 1522); 323 for (p = 0; p < tc->profile_list_count; p++) { 324 tas_prop = &tc->tas_properties[p]; 325 /* tas_calendar_auto_adjust_for_txoverrun<_port#> */ 326 tas_prop->txoverrun = 327 (uint8)soc_property_port_get( 328 unit, (p + 1), spn_TAS_CALENDAR_AUTO_ADJUST_FOR_TXOVERRUN, 0); 329 /* tas_calendar_auto_adjust_for_holdadvance<_port#> */ 330 tas_prop->holdadvance = 331 (uint8)soc_property_port_get( 332 unit, (p + 1), spn_TAS_CALENDAR_AUTO_ADJUST_FOR_HOLDADVANCE, 0); 333 /* tas_calendar_auto_adjust_ref_maxsdu<_port#_cos#> */ 334 /* try "name_port%d_cos%d" for explicit match first */ 335 for (c = 0; c < BCM_COS_COUNT; c++) { 336 #ifndef NDEBUG 337 len = 338 #endif /* !NDEBUG */ 339 sal_snprintf(prop, SOC_PROPERTY_NAME_MAX, "%s_port%d_cos%d", 340 spn_TAS_CALENDAR_AUTO_ADJUST_REF_MAXSDU, p, c); 341 assert(len < SOC_PROPERTY_NAME_MAX); 342 str = soc_property_get_str(unit, prop); 343 if (str != NULL) { 344 tas_prop->maxsdu[c] = _shr_ctoi(str); 345 } else { 346 /* try "name_port%d" for explicit match */ 347 sal_snprintf(prop, SOC_PROPERTY_NAME_MAX, "%s_port%d", 348 spn_TAS_CALENDAR_AUTO_ADJUST_REF_MAXSDU, p); 349 p_str = soc_property_get_str(unit, prop); 350 if (p_str != NULL) { 351 tas_prop->maxsdu[c] = _shr_ctoi(p_str); 352 } else { 353 /* giving default value */ 354 tas_prop->maxsdu[c] = default_sdu; 355 } 356 } 357 } 358 } 359 TAS_UNLOCK(tc); 360 return rv; 361 } 362 363 /* 364 * Function: 365 * bcmi_esw_tas_property_get 366 * Purpose: 367 * Get the soc property value by specifying soc property 368 * with optional suffix (port and cos) 369 * If the property is system wise setting or without optional suffix 370 * specified, the value will be returned by ignoring the lport and cos 371 * parameters. 372 * Parameters: 373 * unit - (IN) unit number 374 * tas_prop - (IN) soc property type (TAS_PROP_XXX) 375 * port - (IN) lport 376 * cos - (IN) cosq 377 * value - (OUT) value 378 * Returns: 379 * BCM_E_XXX 380 */ 381 int 382 bcmi_esw_tas_property_get( 383 int unit, 384 int tas_prop, 385 int port, 386 int cos, 387 int *value) 388 { 389 bcmi_esw_tas_control_t *tc = NULL; 390 int p = port; 391 int c = cos; 392 tas_prop_info_t *prop_info; 393 394 if (value == NULL) { 395 return BCM_E_PARAM; 396 } 397 BCM_IF_ERROR_RETURN(tas_control_get(unit, &tc)); 398 399 if (port == -1) { 400 p = 0; 401 } 402 if ((p < 0) || (p >= tc->profile_list_count)) { 403 return BCM_E_PARAM; 404 } 405 if (cos == -1) { 406 c = 0; 407 } 408 if ((c < 0) || (c >= BCM_COS_COUNT)) { 409 return BCM_E_PARAM; 410 } 411 prop_info = &tc->tas_properties[p]; 412 switch (tas_prop) { 413 case TAS_PROP_TXOVERRUN: 414 /* won't reference cos */ 415 *value = (int)prop_info->txoverrun; 416 break; 417 case TAS_PROP_HOLDADVANCE: 418 /* won't reference cos */ 419 *value = (int)prop_info->holdadvance; 420 break; 421 case TAS_PROP_MAXSDU: 422 /* Valid when txoverrun is considered */ 423 if (prop_info->txoverrun) { 424 if ((port == -1) || (cos == -1)) { 425 /* if port or cos is not specified, 426 * always return default value. 427 */ 428 *value = 1522; 429 } else { 430 *value = prop_info->maxsdu[c]; 431 } 432 } else { 433 return BCM_E_UNAVAIL; 434 } 435 break; 436 default: 437 return BCM_E_UNAVAIL; 438 } 439 return BCM_E_NONE; 440 } 441 442 /* 443 * Function: 444 * bcmi_esw_tas_control_set 445 * Purpose: 446 * Set various configurations for TAS. 447 * Internal function to dispatch to device specific function. 448 * Parameters: 449 * unit - (IN) unit number 450 * port - (IN) gport id 451 * type - (IN) tas control type defined in bcm_cos_tas_control_t 452 * arg - (IN) tas control value 453 * Returns: 454 * BCM_E_XXX 455 * Notes: 456 * Most of the TAS configurations are on port basis. For some configuration 457 * which is on system basis, the gport should assign to -1. 458 */ 459 int 460 bcmi_esw_tas_control_set( 461 int unit, 462 bcm_gport_t port, 463 bcm_cosq_tas_control_t type, 464 int arg) 465 { 466 bcm_port_t lport = -1; 467 bcmi_esw_tas_control_t *tc = NULL; 468 const tas_drv_t *td; 469 470 if (type == bcmCosqTASControlTASPTPLock) { 471 /* bcmCosqTASControlTASPTPLock only take gport=-1 */ 472 if (port != BCM_GPORT_INVALID) { 473 return BCM_E_PARAM; 474 } 475 } else { 476 BCM_IF_ERROR_RETURN(tas_gport_validate(unit, port, &lport)); 477 } 478 479 BCM_IF_ERROR_RETURN(tas_control_get(unit, &tc)); 480 481 td = tc->tas_drvs; 482 if (td->tas_control_set != NULL) { 483 return td->tas_control_set(unit, lport, type, arg); 484 } 485 486 return BCM_E_UNAVAIL; 487 } 488 489 /* 490 * Function: 491 * bcmi_esw_tas_control_get 492 * Purpose: 493 * Get various configurations for TAS. 494 * Internal function to dispatch to device specific function. 495 * Parameters: 496 * unit - (IN) unit number 497 * port - (IN) gport id 498 * type - (IN) tas control type defined in bcm_cos_tas_control_t 499 * arg - (OUT) tas control value 500 * Returns: 501 * BCM_E_XXX 502 * Notes: 503 * Most of the TAS configurations are on port basis. For some configuration 504 * which is on system basis, the gport should assign to -1. 505 */ 506 int 507 bcmi_esw_tas_control_get( 508 int unit, 509 bcm_gport_t port, 510 bcm_cosq_tas_control_t type, 511 int *arg) 512 { 513 bcm_port_t lport = -1; 514 bcmi_esw_tas_control_t *tc = NULL; 515 const tas_drv_t *td; 516 517 if (type == bcmCosqTASControlTASPTPLock) { 518 /* bcmCosqTASControlTASPTPLock only take gport=-1 */ 519 if (port != BCM_GPORT_INVALID) { 520 return BCM_E_PARAM; 521 } 522 } else { 523 BCM_IF_ERROR_RETURN(tas_gport_validate(unit, port, &lport)); 524 } 525 BCM_IF_ERROR_RETURN(tas_control_get(unit, &tc)); 526 527 td = tc->tas_drvs; 528 if (td->tas_control_get != NULL) { 529 return td->tas_control_get(unit, lport, type, arg); 530 } 531 532 return BCM_E_UNAVAIL; 533 } 534 535 /* 536 * Function: 537 * bcm_esw_tas_status_get 538 * Purpose: 539 * Get TAS status by specifying the type. 540 * Internal function to dispatch to device specific function. 541 * Parameters: 542 * unit - (IN) unit number 543 * port - (IN) gport id 544 * type - (IN) tas status type defined in bcm_cos_tas_status_t 545 * arg - (OUT) tas status value 546 * Returns: 547 * BCM_E_XXX 548 */ 549 int 550 bcmi_esw_tas_status_get( 551 int unit, 552 bcm_gport_t port, 553 bcm_cosq_tas_status_t type, 554 int *arg) 555 { 556 bcmi_esw_tas_control_t *tc = NULL; 557 bcm_port_t lport; 558 const tas_drv_t *td; 559 560 BCM_IF_ERROR_RETURN(tas_gport_validate(unit, port, &lport)); 561 BCM_IF_ERROR_RETURN(tas_control_get(unit, &tc)); 562 563 td = tc->tas_drvs; 564 if (td->tas_status_get != NULL) { 565 return td->tas_status_get(unit, lport, type, arg); 566 } 567 return BCM_E_UNAVAIL; 568 } 569 570 /* Time helper function */ 571 #define TAS_PTP_STACK_ID (0) 572 #define TAS_PTP_CLOCK_NUM (0) 573 /* 574 * Function: 575 * bcmi_tas_current_time 576 * Purpose: 577 * Get the current PTP time 578 * Parameters: 579 * unit - (IN) unit number 580 * current_time - (OUT) current time 581 * Returns: 582 * BCM_E_XXX 583 */ 584 int 585 bcmi_tas_current_time(int unit, bcm_ptp_timestamp_t *current_time) 586 { 587 int rv = BCM_E_UNAVAIL; 588 char s[32]; 589 590 if (current_time == NULL) { 591 return BCM_E_PARAM; 592 } 593 #if defined(INCLUDE_PTP) 594 if (soc_feature(unit, soc_feature_ptp) || 595 soc_feature(unit, soc_feature_use_local_1588)) { 596 rv = bcm_esw_ptp_clock_time_get(unit, TAS_PTP_STACK_ID, 597 TAS_PTP_CLOCK_NUM, current_time); 598 } else 599 #endif 600 { 601 return BCM_E_UNAVAIL; 602 } 603 if (bsl_check(bslLayerBcm, bslSourceTas, bslSeverityDebug, unit)) { 604 _shr_format_uint64_hexa_string(current_time->seconds, s); 605 LOG_DEBUG(BSL_LS_BCM_TAS, 606 (BSL_META_U(unit, "Time stamp: sec: %s ns %09u\n"), 607 s, (unsigned)current_time->nanoseconds)); 608 } 609 return rv; 610 } 611 612 /* 613 * Function: 614 * bcmi_tas_ptp_to_ns 615 * Purpose: 616 * Helper function to covert ptp to nanoseconds. 617 * Parameters: 618 * ptp_time - (IN) ptp time in bcm_ptp_timestamp_t format 619 * Returns: 620 * time in nanoseconds 621 */ 622 uint64 623 bcmi_tas_ptp_to_ns(bcm_ptp_timestamp_t ptp_time) 624 { 625 uint64 time; 626 uint32 one_sec = TAS_PTP_TIME_NANOSEC_MAX; 627 628 COMPILER_64_COPY(time, ptp_time.seconds); 629 COMPILER_64_UMUL_32(time, one_sec); 630 COMPILER_64_ADD_32(time, ptp_time.nanoseconds); 631 632 return time; 633 } 634 635 /* 636 * Function: 637 * bcmi_tas_ns_to_ptp 638 * Purpose: 639 * Helper function to covert nanoseconds to PTP 640 * Parameters: 641 * ns - (IN) time in nanoseconds 642 * ptp_time - (OUT) ptp time in bcm_ptp_timestamp_t format 643 */ 644 void 645 bcmi_tas_ns_to_ptp(uint64 ns, bcm_ptp_timestamp_t *ptp_time) 646 { 647 uint64 one_sec, sec; 648 uint32 nsec; 649 650 if (ptp_time == NULL) { 651 LOG_ERROR(BSL_LS_BCM_TAS, 652 (BSL_META("ptp_time ptr is NULL !\n"))); 653 return; 654 } 655 /* temp parameter to do 64bit operation */ 656 COMPILER_64_SET(one_sec, 0, TAS_PTP_TIME_NANOSEC_MAX); 657 COMPILER_64_COPY(sec, ns); 658 659 /* sec = ns/TAS_PTP_TIME_NANOSEC_MAX */ 660 COMPILER_64_UDIV_64(sec, one_sec); 661 ptp_time->seconds = sec; 662 663 /* nsec = ns % TAS_PTP_TIME_NANOSEC_MAX; */ 664 /* mod(x,y) = x - y*int(x/y) */ 665 COMPILER_64_UMUL_32(sec, TAS_PTP_TIME_NANOSEC_MAX); 666 COMPILER_64_SUB_64(ns, sec); 667 COMPILER_64_TO_32_LO(nsec, ns); 668 669 ptp_time->nanoseconds = nsec; 670 } 671 672 /* 673 * Function: 674 * bcmi_esw_tas_profile_delay_param_get 675 * Purpose: 676 * Helper function to get the device-specific delay paramaters which are 677 * used to do the profile entry remap. 678 * 679 * Parameters: 680 * unit - (IN) unit number 681 * tas_delay_param - (IN) TAS_DPARAM_xxx to specify which delay param 682 * port - (IN) logical port 683 * qmap - (IN) queue bitmap, optional and valid for type 684 * TAS_DPARAM_TGCR_DYNAMIC. 685 * value - (OUT) value in ns 686 * Returns: 687 * BCM_E_XXX 688 */ 689 int 690 bcmi_esw_tas_profile_delay_param_get( 691 int unit, 692 int tas_delay_param, 693 bcm_port_t port, 694 uint32 qmap, 695 int *value) 696 { 697 bcmi_esw_tas_control_t *tc = NULL; 698 const tas_drv_t *td; 699 700 BCM_IF_ERROR_RETURN(tas_control_get(unit, &tc)); 701 702 td = tc->tas_drvs; 703 if (td->tas_profile_delay_param_get != NULL) { 704 return td->tas_profile_delay_param_get(unit, tas_delay_param, port, 705 qmap, value); 706 } 707 return BCM_E_UNAVAIL; 708 } 709 710 /* 711 * Function: 712 * bcmi_tas_profile_entries_remap 713 * Purpose: 714 * Entry remap function. 715 * To mitigate the Tx overrun on gate closure and Hold-Advance when 716 * preemption is enabled, extra entries might be added. 717 * And the remap algorithm is general but the delay parmeters 718 * are device dependent. 719 * 720 * Parameters: 721 * unit - (IN) unit number 722 * lport - (IN) logical port 723 * num_entries - (IN) numbers of entries in tas entries 724 * entries - (IN) tas entries 725 * num_new_entries - (OUT) numbers of remapped entries 726 * new_entries - (OUT) remapped tas entries 727 * Returns: 728 * BCM_E_XXX 729 */ 730 STATIC int 731 bcmi_tas_profile_entries_remap( 732 int unit, 733 bcm_port_t lport, 734 int num_entries, 735 bcm_cosq_tas_entry_t *entries, 736 int *num_new_entries, 737 bcm_cosq_tas_entry_t **new_entries) 738 { 739 bcm_cosq_tas_entry_t *hw_entries = NULL, *tas_entry, *n_tas_entry; 740 bcm_gport_t gport; 741 uint8 preemption_enable = 0, last_valid_entry; 742 int rv = BCM_E_UNAVAIL; 743 int prop_tgcr, prop_tha, tgcr, tgcr_txpkt, tha, tgcr_ticks, tha_ticks; 744 int tgcr_fix; 745 int i, num_hw_entries, ticks, extra_enties, hw_index; 746 uint32 status, preempt_bmp = 0, o_phold = 0, phold = 0; 747 uint32 o_qstate, qstate, xor_qstate, qdiff_tgcr, qdiff_tha; 748 749 if (num_new_entries == NULL) { 750 return BCM_E_PARAM; 751 } 752 if (new_entries == NULL) { 753 return BCM_E_PARAM; 754 } 755 BCM_IF_ERROR_RETURN(bcm_esw_port_gport_get(unit, lport, &gport)); 756 757 /* Get the soc property */ 758 BCM_IF_ERROR_RETURN( 759 bcmi_esw_tas_property_get(unit, TAS_PROP_TXOVERRUN, lport, 760 -1, &prop_tgcr)); 761 BCM_IF_ERROR_RETURN( 762 bcmi_esw_tas_property_get(unit, TAS_PROP_HOLDADVANCE, lport, 763 -1, &prop_tha)); 764 if ((prop_tgcr == 0) && (prop_tha == 0)) { 765 /* We don't need to do entry remap, simply copy and return */ 766 /* Create remap entries */ 767 num_hw_entries = num_entries; 768 TAS_ALLOC(unit, hw_entries, bcm_cosq_tas_entry_t, 769 sizeof(bcm_cosq_tas_entry_t) * num_hw_entries, 770 "tas profile hw entries", 0, rv); 771 if (BCM_FAILURE(rv)) { 772 return rv; 773 } 774 sal_memcpy(hw_entries, entries, 775 sizeof(bcm_cosq_tas_entry_t) * num_hw_entries); 776 *new_entries = hw_entries; 777 *num_new_entries = num_hw_entries; 778 return BCM_E_NONE; 779 } 780 781 BCM_IF_ERROR_RETURN( 782 bcm_esw_cosq_tas_control_get( 783 unit, gport, bcmCosqTASControlGateControlTickInterval, 784 &ticks)); 785 786 /* Check if Preemption is active */ 787 if (soc_feature(unit, soc_feature_preemption)) { 788 status = bcmPortPreemptStatusTxInactive; 789 rv = bcm_esw_port_preemption_status_get(unit, gport, 790 bcmPortPreemptStatusTx, 791 &status); 792 if (BCM_SUCCESS(rv) && (status == bcmPortPreemptStatusTxActive)) { 793 preemption_enable = 1; 794 BCM_IF_ERROR_RETURN( 795 bcm_esw_port_preemption_control_get( 796 unit, gport, bcmPortPreemptControlQueueBitmap, 797 &preempt_bmp)); 798 } 799 } 800 801 /* Calculate the number of the extra entries */ 802 /* initialize the old entry state o_qstate = the entry[0] state */ 803 o_qstate = entries[0].state; 804 extra_enties = 0; 805 last_valid_entry = 0; 806 for (i = 1; i < num_entries; i++) { 807 tas_entry = &entries[i]; 808 if ((tas_entry->ticks == BCM_COSQ_TAS_ENTRY_TICKS_GO_FIRST) || 809 (last_valid_entry)) { 810 /* Do not compare with the entry with interval == 0 where the 811 * entry state will not be referenced. 812 */ 813 break; 814 } 815 if (tas_entry->ticks == BCM_COSQ_TAS_ENTRY_TICKS_STAY) { 816 /* 817 * For ticks stay entry, its state will be referenced. 818 * Still need to do the remap. But should leave in the 819 * next loop. 820 */ 821 last_valid_entry = 1; 822 } 823 qstate = tas_entry->state; 824 /* Get the 0->1 or 1->0 change bitmap */ 825 xor_qstate = o_qstate ^ qstate; 826 if (prop_tgcr) { 827 /* check if any 1 -> 0 change */ 828 qdiff_tgcr = xor_qstate & o_qstate; 829 if (qdiff_tgcr) { 830 extra_enties++; 831 o_qstate = qstate; 832 continue; 833 } 834 } 835 if (preemption_enable) { 836 if (prop_tha) { 837 /* Tha is required only when preemption is enabled. */ 838 /* check if any 0 -> 1 change on express queue */ 839 qdiff_tha = xor_qstate & qstate; 840 qdiff_tha &= ~preempt_bmp; 841 if (qdiff_tha) { 842 extra_enties++; 843 o_qstate = qstate; 844 continue; 845 } 846 } 847 } 848 o_qstate = qstate; 849 } 850 851 if (prop_tgcr) { 852 /* Get the fixed tgcr value exclude tgcr_txpkt value which depends on 853 * the queue */ 854 BCM_IF_ERROR_RETURN( 855 bcmi_esw_tas_profile_delay_param_get(unit, TAS_DPARAM_TGCR_FIXED, 856 lport, 0, &tgcr_fix)); 857 } 858 if (prop_tha && preemption_enable) { 859 /* Get the Tha value */ 860 BCM_IF_ERROR_RETURN( 861 bcmi_esw_tas_profile_delay_param_get(unit, TAS_DPARAM_THA, 862 lport, 0, &tha)); 863 } 864 /* Create remap entries */ 865 num_hw_entries = num_entries + extra_enties; 866 TAS_ALLOC(unit, hw_entries, bcm_cosq_tas_entry_t, 867 sizeof(bcm_cosq_tas_entry_t) * num_hw_entries, 868 "tas profile hw entries", 0, rv); 869 if (BCM_FAILURE(rv)) { 870 return rv; 871 } 872 /* Assign the remap entires */ 873 /* Initialize the old entry state o_qstate = the entry[0] state */ 874 o_qstate = entries[0].state; 875 hw_index = 0; 876 last_valid_entry = 0; 877 /* Start from user entry[1] */ 878 for (i = 1; i < num_entries; i++) { 879 o_phold = 0; 880 phold = 0; 881 qdiff_tgcr = 0; 882 qdiff_tha = 0; 883 /* 884 * Remap decision : according to the difference between two continuous 885 * user entries. 886 */ 887 n_tas_entry = &entries[i]; 888 tas_entry = &entries[i - 1]; 889 if (last_valid_entry == 1) { 890 /* When the last valid_entry hit, leave the loop */ 891 break; 892 } 893 if (n_tas_entry->ticks == BCM_COSQ_TAS_ENTRY_TICKS_GO_FIRST) { 894 /* 895 * Do not compare with the entry with interval == 0 where the 896 * entry state will not be referenced. 897 * Directly write i-1 entry and leave the for loop. 898 */ 899 sal_memcpy(&hw_entries[hw_index], tas_entry, 900 sizeof(bcm_cosq_tas_entry_t)); 901 hw_index++; 902 break; 903 } else { 904 if (n_tas_entry->ticks == BCM_COSQ_TAS_ENTRY_TICKS_STAY) { 905 /* 906 * For ticks stay entry, its state will be referenced. 907 * Still need to do the remap. But should leave in the 908 * next loop. 909 */ 910 last_valid_entry = 1; 911 } 912 /* Get the next user entry state */ 913 qstate = n_tas_entry->state; 914 /* Any 0->1 or 1->0 change bitmap */ 915 xor_qstate = o_qstate ^ qstate; 916 if (prop_tgcr) { 917 /* 918 * To consider Tgcr case : 919 * Any gate open to close (1 -> 0) change need the Tgcr 920 */ 921 qdiff_tgcr = xor_qstate & o_qstate; 922 } 923 if (preemption_enable) { 924 /* 925 * When preemption is enabled, any expess queue is open, 926 * the phold should be 1. 927 */ 928 o_phold = o_qstate & ~preempt_bmp; 929 if (prop_tha) { 930 /* 931 * To consider Tha case : 932 * Tha is required only when preemption is enabled. 933 * Any express queue gate from close to open need Tha. 934 * If any express queue has gate from open to close, 935 * we need to consider Tgcr instead. 936 */ 937 if (qdiff_tgcr & ~preempt_bmp) { 938 qdiff_tha = 0; 939 } else { 940 qdiff_tha = xor_qstate & qstate; 941 qdiff_tha &= ~preempt_bmp; 942 } 943 } 944 if (qdiff_tgcr) { 945 /* 946 * Any express queue has 1->0 change : set phold request 947 * to prevent preemptable traffic tx overrun 948 */ 949 phold = qdiff_tgcr & ~preempt_bmp; 950 } 951 } 952 } 953 954 /* hw_index used to program to remapped(hw) table */ 955 if (hw_index >= num_hw_entries) { 956 /* There must have something wrong that the hw_index exceed 957 * num_hw_entries. */ 958 TAS_FREE(unit, hw_entries, 0); 959 return BCM_E_INTERNAL; 960 } 961 /* Tha has higher precedence */ 962 if (qdiff_tha) { 963 /* Validate the Tha against the entry->ticks */ 964 tha_ticks = (tha + ticks - 1) / ticks; 965 if (tha_ticks >= tas_entry->ticks) { 966 LOG_ERROR(BSL_LS_BCM_TAS, 967 (BSL_META_U(unit, "System required Hold Advance time" 968 " Tha tick %d beyond the calendar table " 969 "entry[%d]ticks %d\n"), 970 tha_ticks, i, tas_entry->ticks)); 971 TAS_FREE(unit, hw_entries, 0); 972 return BCM_E_PARAM; 973 } 974 /* 975 * Adjust the entries : 976 * new entry state = previous entry state 977 * previous entry tick = Ti - Tha 978 * new entry tick = Tha 979 * previous entry hold_request = o_phold 980 * new entry hold_request = 1 981 */ 982 hw_entries[hw_index].ticks = tas_entry->ticks - tha_ticks; 983 hw_entries[hw_index].state = tas_entry->state; 984 if (o_phold) { 985 hw_entries[hw_index].flags = tas_entry->flags | 986 BCM_COSQ_TAS_ENTRY_F_PREEMPT; 987 } else { 988 hw_entries[hw_index].flags = tas_entry->flags & 989 ~BCM_COSQ_TAS_ENTRY_F_PREEMPT; 990 } 991 hw_index++; 992 hw_entries[hw_index].ticks = tha_ticks; 993 hw_entries[hw_index].state = tas_entry->state; 994 hw_entries[hw_index].flags = tas_entry->flags | 995 BCM_COSQ_TAS_ENTRY_F_PREEMPT; 996 } else if (qdiff_tgcr) { 997 /* 998 * Tgcr dynamic value need to include the tgcr_txpkt vlaue which is 999 * depending on the specified queue. 1000 */ 1001 rv = bcmi_esw_tas_profile_delay_param_get( 1002 unit, TAS_DPARAM_TGCR_DYNAMIC, lport, qdiff_tgcr, 1003 &tgcr_txpkt); 1004 if (BCM_FAILURE(rv)) { 1005 TAS_FREE(unit, hw_entries, 0); 1006 return rv; 1007 } 1008 1009 tgcr = tgcr_fix + tgcr_txpkt; 1010 tgcr_ticks = (tgcr + ticks - 1) / ticks; 1011 /* Validate the Tgcr against the entry->ticks */ 1012 if (tgcr_ticks >= tas_entry->ticks) { 1013 LOG_ERROR(BSL_LS_BCM_TAS, 1014 (BSL_META_U(unit, "System required gate close " 1015 "response time Tgcr tick %d beyond the " 1016 "calendar table entry[%d]ticks %d\n"), 1017 tgcr_ticks, i, tas_entry->ticks)); 1018 TAS_FREE(unit, hw_entries, 0); 1019 return BCM_E_PARAM; 1020 } 1021 /* 1022 * Adjust the entries : 1023 * new entry state = 0 (all closed) 1024 * previous entry tick = Ti - Tgcr 1025 * new entry tick = tgcr 1026 * previous entry hold_request = o_phold 1027 * new entry hold_request = phold 1028 */ 1029 hw_entries[hw_index].ticks = tas_entry->ticks - tgcr_ticks; 1030 hw_entries[hw_index].state = tas_entry->state; 1031 if (o_phold) { 1032 hw_entries[hw_index].flags = tas_entry->flags | 1033 BCM_COSQ_TAS_ENTRY_F_PREEMPT; 1034 } else { 1035 hw_entries[hw_index].flags = tas_entry->flags & 1036 ~BCM_COSQ_TAS_ENTRY_F_PREEMPT; 1037 } 1038 hw_index++; 1039 hw_entries[hw_index].ticks = tgcr_ticks; 1040 hw_entries[hw_index].state = 0; 1041 if (phold) { 1042 hw_entries[hw_index].flags = tas_entry->flags | 1043 BCM_COSQ_TAS_ENTRY_F_PREEMPT; 1044 } else { 1045 hw_entries[hw_index].flags = tas_entry->flags & 1046 ~BCM_COSQ_TAS_ENTRY_F_PREEMPT; 1047 } 1048 } else { 1049 /* no need to adjust */ 1050 sal_memcpy(&hw_entries[hw_index], tas_entry, 1051 sizeof(bcm_cosq_tas_entry_t)); 1052 } 1053 hw_index++; 1054 o_qstate = qstate; 1055 } 1056 1057 if (hw_index >= num_hw_entries) { 1058 /* 1059 * There must have something wrong that the hw_index exceed 1060 * num_hw_entries. 1061 */ 1062 TAS_FREE(unit, hw_entries, 0); 1063 return BCM_E_INTERNAL; 1064 } 1065 /* Program the last effective entry. 1066 * We do not compare the last entry with the first one 1067 */ 1068 if (hw_index == 0) { 1069 /* Consider the case when num_entries == 1 */ 1070 tas_entry = &entries[0]; 1071 } else { 1072 /* Update the last entry to HW table */ 1073 if (i < num_entries) { 1074 /* GO_FIRST or STAY break case */ 1075 tas_entry = &entries[i]; 1076 } else { 1077 tas_entry = &entries[num_entries - 1]; 1078 } 1079 } 1080 sal_memcpy(&hw_entries[hw_index], tas_entry, 1081 sizeof(bcm_cosq_tas_entry_t)); 1082 1083 *new_entries = hw_entries; 1084 *num_new_entries = num_hw_entries; 1085 1086 return BCM_E_NONE; 1087 } 1088 1089 /* 1090 * Function: 1091 * bcmi_tas_profile_idx_get 1092 * Purpose: 1093 * Get the inactive hw index. We need to program to the inactive sets 1094 * Parameters: 1095 * unit - (IN) unit number 1096 * lport - (IN) logical port 1097 * config_idx - (OUT) inactive hw index 1098 * Returns: 1099 * BCM_E_XXX 1100 */ 1101 STATIC int 1102 bcmi_tas_profile_idx_get(int unit, bcm_port_t lport, int *config_idx) 1103 { 1104 bcmi_esw_tas_control_t *tc = NULL; 1105 const tas_drv_t *td; 1106 int rv = BCM_E_UNAVAIL; 1107 1108 BCM_IF_ERROR_RETURN(tas_control_get(unit, &tc)); 1109 1110 td = tc->tas_drvs; 1111 if (td->tas_profile_idx_get != NULL) { 1112 rv = td->tas_profile_idx_get(unit, lport, config_idx); 1113 } 1114 return rv; 1115 } 1116 1117 /* 1118 * Function: 1119 * bcmi_tas_profile_entries_write 1120 * Purpose: 1121 * Program the profile entries to HW 1122 * Parameters: 1123 * unit - (IN) unit number 1124 * lport - (IN) logical port 1125 * config_idx - (IN) hw config idx 1126 * entries - (IN) profile entries 1127 * num_entries - (IN) number of entries 1128 * Returns: 1129 * BCM_E_XXX 1130 */ 1131 STATIC int 1132 bcmi_tas_profile_entries_write( 1133 int unit, 1134 bcm_port_t lport, 1135 int config_idx, 1136 bcm_cosq_tas_entry_t *entries, 1137 int num_entries) 1138 { 1139 bcmi_esw_tas_control_t *tc = NULL; 1140 const tas_drv_t *td; 1141 int rv = BCM_E_UNAVAIL; 1142 1143 BCM_IF_ERROR_RETURN(tas_control_get(unit, &tc)); 1144 1145 td = tc->tas_drvs; 1146 if (td->tas_profile_entries_write != NULL) { 1147 rv = td->tas_profile_entries_write(unit, lport, config_idx, entries, 1148 num_entries); 1149 } 1150 return rv; 1151 } 1152 1153 /* 1154 * Function: 1155 * bcmi_tas_profile_schedule_config 1156 * Purpose: 1157 * Device specific function to schedule the proper time to program the 1158 * time information to HW. Also provide the callback function to call when 1159 * the time information programmed to HW and kick-off the config change. 1160 * In the callback function, the profile state should be changed to 1161 * "committed". 1162 * Parameters: 1163 * unit - (IN) unit number 1164 * lport - (IN) logical port 1165 * base_time - (IN) new base time 1166 * cycle_time - (IN) new cycle time 1167 * cycle_extension - (IN) new cycle extension 1168 * cb - (IN) cb function to call when the time information 1169 * programmed to HW and kick-off the 1170 * config change. 1171 * fn_data - (IN) fn_data to supply in the callback 1172 * Returns: 1173 * BCM_E_XXX 1174 */ 1175 STATIC int 1176 bcmi_tas_profile_schedule_config(int unit, bcm_port_t lport, 1177 bcm_ptp_timestamp_t base_time, 1178 uint32 cycle_time, uint32 cycle_extension, 1179 profile_commit_cb_fn cb, void *fn_data) 1180 { 1181 bcmi_esw_tas_control_t *tc = NULL; 1182 const tas_drv_t *td; 1183 int rv = BCM_E_UNAVAIL; 1184 1185 BCM_IF_ERROR_RETURN(tas_control_get(unit, &tc)); 1186 1187 td = tc->tas_drvs; 1188 if (td->tas_profile_schedule_config != NULL) { 1189 rv = td->tas_profile_schedule_config(unit, lport, base_time, 1190 cycle_time, cycle_extension, 1191 cb, fn_data); 1192 } 1193 return rv; 1194 } 1195 1196 /* 1197 * Function: 1198 * bcmi_tas_profile_change 1199 * Purpose: 1200 * Issue the config change to HW. 1201 * Used for non-PTP mode. 1202 * Parameters: 1203 * unit - (IN) unit number 1204 * port - (IN) logical port 1205 * Returns: 1206 * BCM_E_XXX 1207 */ 1208 STATIC int 1209 bcmi_tas_profile_change(int unit, bcm_port_t lport) 1210 { 1211 bcmi_esw_tas_control_t *tc = NULL; 1212 const tas_drv_t *td; 1213 int rv = BCM_E_UNAVAIL; 1214 1215 BCM_IF_ERROR_RETURN(tas_control_get(unit, &tc)); 1216 1217 td = tc->tas_drvs; 1218 if (td->tas_profile_change != NULL) { 1219 rv = td->tas_profile_change(unit, lport); 1220 } 1221 return rv; 1222 } 1223 1224 /* 1225 * Function: 1226 * tas_pid_get 1227 * Purpose: 1228 * Get the profile id by specifying port 1229 * Parameters: 1230 * unit - (IN) unit number 1231 * lport - (IN) logical port 1232 * pid - (OUT) profile id 1233 * Returns: 1234 * BCM_E_XXX 1235 */ 1236 STATIC int 1237 tas_pid_get(int unit, bcm_port_t lport, bcm_cosq_tas_profile_id_t *pid) 1238 { 1239 int max_count; /* Maximum number of pid to try */ 1240 static uint32 last_allocated_pid = 0; 1241 tas_profile_ctrl_t *tp; 1242 bcm_cosq_tas_profile_id_t temp_pid; 1243 int rv = BCM_E_NONE; 1244 1245 /* pid index should be 1 ~ TAS_PID_IDX_MASK */ 1246 max_count = TAS_PID_IDX_MASK; 1247 1248 while (max_count--) { 1249 /* increse the pid index */ 1250 last_allocated_pid++; 1251 /* Handle the wrap case */ 1252 if (TAS_PID_IDX_MASK == last_allocated_pid) { 1253 last_allocated_pid = 1; 1254 } 1255 /* Check the pid is used or not */ 1256 temp_pid = last_allocated_pid | (lport << TAS_PID_PORT_START_BIT); 1257 rv = tas_profile_ctrl_get(unit, temp_pid, &tp); 1258 if (BCM_E_NOT_FOUND == rv) { 1259 /* Not used by others, take this as for the new profile */ 1260 *pid = temp_pid; 1261 return (BCM_E_NONE); 1262 } 1263 if (BCM_FAILURE(rv)) { 1264 return (rv); 1265 } 1266 } 1267 return (BCM_E_RESOURCE); 1268 } 1269 1270 /* 1271 * Function: 1272 * tas_profile_profile_param_validate 1273 * Purpose: 1274 * Parameter check for bcmi_esw_tas_profile_create 1275 * Parameters: 1276 * unit - (IN) unit number 1277 * port - (IN) gport 1278 * profile - (IN) bcm profile structure 1279 * Returns: 1280 * BCM_E_XXX 1281 */ 1282 STATIC int 1283 tas_profile_profile_param_validate( 1284 int unit, 1285 bcm_gport_t port, 1286 bcm_cosq_tas_profile_t *profile) 1287 { 1288 bcm_ptp_timestamp_t *base_time; 1289 uint32 cycle_time, cycle_extension; 1290 int ptp_mode, gclt_size; 1291 bcmi_esw_tas_control_t *tc = NULL; 1292 const tas_drv_t *td; 1293 1294 /* TAS(bcmCosqTASControlTASEnable) is not required during profile create 1295 * Check ptp_mode for time parameter validation. 1296 * PTP lock (bcmCosqTASControlTASPTPLock) when ptp_mode = 1 is not required 1297 * during profile create. 1298 */ 1299 BCM_IF_ERROR_RETURN( 1300 bcmi_esw_tas_control_get(unit, port, bcmCosqTASControlUsePTPTime, 1301 &ptp_mode)); 1302 base_time = &profile->ptp_base_time; 1303 cycle_time = profile->ptp_cycle_time; 1304 cycle_extension = profile->ptp_max_cycle_extension; 1305 if (ptp_mode) { 1306 /* ptp_base should be non-zeros. */ 1307 if (COMPILER_64_IS_ZERO(base_time->seconds) && 1308 (base_time->nanoseconds == 0)) { 1309 return BCM_E_PARAM; 1310 } 1311 /* cycle_time should > cycle extension time */ 1312 if (cycle_extension >= cycle_time) { 1313 return BCM_E_PARAM; 1314 } 1315 } else { 1316 /* ptp_base should be zeros. */ 1317 if (!COMPILER_64_IS_ZERO(base_time->seconds) || 1318 (base_time->nanoseconds != 0) || 1319 (cycle_time != 0) || 1320 (cycle_extension != 0)) { 1321 return BCM_E_PARAM; 1322 } 1323 } 1324 1325 BCM_IF_ERROR_RETURN( 1326 bcmi_esw_tas_status_get(unit, port, bcmCosqTASStatusMaxCalendarEntries, 1327 &gclt_size)); 1328 /* profile->num_entries should <= device GCLT size */ 1329 if (profile->num_entries > gclt_size) { 1330 return BCM_E_PARAM; 1331 } 1332 /* profile->num_entries should > 0 */ 1333 if (profile->num_entries <= 0) { 1334 return BCM_E_PARAM; 1335 } 1336 /* The first entry should not specify GO_FIRST. */ 1337 if (profile->entries[0].ticks == 1338 BCM_COSQ_TAS_ENTRY_TICKS_GO_FIRST) { 1339 return BCM_E_PARAM; 1340 } 1341 1342 BCM_IF_ERROR_RETURN(tas_control_get(unit, &tc)); 1343 1344 td = tc->tas_drvs; 1345 if (td->tas_profile_param_check != NULL) { 1346 return td->tas_profile_param_check(unit, profile); 1347 } 1348 1349 return BCM_E_NONE; 1350 } 1351 1352 /* 1353 * Function: 1354 * tas_profile_create 1355 * Purpose: 1356 * The internal profile resource is created in this function. 1357 * 1358 * Parameters: 1359 * unit - (IN) unit number 1360 * lport - (IN) logical port 1361 * profile - (IN) bcm profile 1362 * pid - (OUT) profile id 1363 * Returns: 1364 * BCM_E_XXX 1365 */ 1366 STATIC int 1367 tas_profile_create( 1368 int unit, 1369 bcm_port_t lport, 1370 bcm_cosq_tas_profile_t *profile, 1371 bcm_cosq_tas_profile_id_t *pid) 1372 { 1373 bcmi_esw_tas_control_t *tc = NULL; 1374 tas_profile_ctrl_t *tp; 1375 int num_entries, count = 0; 1376 int rv = BCM_E_NONE; 1377 1378 BCM_IF_ERROR_RETURN(tas_control_get(unit, &tc)); 1379 1380 TAS_LOCK(tc); 1381 1382 TAS_PROFILE_ITER(tc->profile_list, tp, lport) { 1383 count++; 1384 } 1385 1386 if (count >= MAX_TAS_PROFILE_CNT) { 1387 LOG_ERROR(BSL_LS_BCM_TAS, 1388 (BSL_META_U(unit, "Exceed supported profile count %d\n"), 1389 MAX_TAS_PROFILE_CNT)); 1390 TAS_UNLOCK(tc); 1391 return BCM_E_RESOURCE; 1392 } 1393 /* Create profile structure */ 1394 TAS_ALLOC(unit, tp, tas_profile_ctrl_t, 1395 sizeof(tas_profile_ctrl_t), 1396 "tas profile", 0, rv); 1397 if (BCM_FAILURE(rv)) { 1398 TAS_UNLOCK(tc); 1399 return rv; 1400 } 1401 /* Get profile id */ 1402 rv = tas_pid_get(unit, lport, pid); 1403 if (BCM_FAILURE(rv)) { 1404 TAS_FREE(unit, tp, 0); 1405 TAS_UNLOCK(tc); 1406 return rv; 1407 } 1408 /* Create profile lock */ 1409 tp->profile_mutex = sal_mutex_create("tas_profile.lock"); 1410 if (NULL == tp->profile_mutex) { 1411 TAS_FREE(unit, tp, 0); 1412 TAS_UNLOCK(tc); 1413 return BCM_E_RESOURCE; 1414 } 1415 1416 num_entries = profile->num_entries; 1417 /* Create tp->user_entries */ 1418 TAS_ALLOC(unit, tp->user_entries, bcm_cosq_tas_entry_t, 1419 sizeof(bcm_cosq_tas_entry_t) * num_entries, 1420 "tas profile entries", 0, rv); 1421 if (BCM_FAILURE(rv)) { 1422 sal_mutex_destroy(tp->profile_mutex); 1423 TAS_FREE(unit, tp, 0); 1424 TAS_UNLOCK(tc); 1425 return rv; 1426 } 1427 1428 /* Initialize profile id. */ 1429 tp->port = lport; 1430 tp->pid = *pid; 1431 tp->pstate = bcmCosqTASProfileInit; 1432 tp->hw_index = -1; 1433 tp->num_user_entries = num_entries; 1434 1435 /* copy valid profile->entries to tp->user_entries */ 1436 sal_memcpy(tp->user_entries, profile->entries, 1437 sizeof(bcm_cosq_tas_entry_t) * num_entries); 1438 1439 sal_memcpy(&tp->base_time, &profile->ptp_base_time, 1440 sizeof(bcm_ptp_timestamp_t)); 1441 1442 tp->cycle_time = profile->ptp_cycle_time; 1443 tp->cycle_extension = profile->ptp_max_cycle_extension; 1444 1445 /* Insert profile to tas profile set */ 1446 TAS_PROFILE_INSERT(tc->profile_list, tp, lport); 1447 1448 TAS_UNLOCK(tc); 1449 1450 return BCM_E_NONE; 1451 } 1452 1453 /* 1454 * Function: 1455 * tas_profile_id_validate 1456 * Purpose: 1457 * Validate the profile id 1458 * Parameters: 1459 * unit - (IN) unit number 1460 * port - (IN) gport 1461 * pid - (IN) profile id 1462 * lport - (OUT) logical port 1463 * Returns: 1464 * BCM_E_XXX 1465 */ 1466 STATIC int 1467 tas_profile_id_validate( 1468 int unit, 1469 bcm_gport_t port, 1470 bcm_cosq_tas_profile_id_t pid, 1471 bcm_port_t *lport) 1472 { 1473 bcm_port_t local_port; 1474 1475 BCM_IF_ERROR_RETURN(tas_gport_validate(unit, port, &local_port)); 1476 1477 if (lport != NULL) { 1478 *lport = local_port; 1479 } 1480 if (local_port != ((pid >> TAS_PID_PORT_START_BIT) & TAS_PID_IDX_MASK)) { 1481 LOG_DEBUG(BSL_LS_BCM_TAS, 1482 (BSL_META_U(unit, 1483 "Profile id is not associated with the port."))); 1484 return BCM_E_PARAM; 1485 } 1486 return BCM_E_NONE; 1487 } 1488 1489 /* 1490 * Function: 1491 * tas_gclt_entries_remap 1492 * Purpose: 1493 * Remap the profile user entries and update the rempped one 1494 * to internal profile structure 1495 * Parameters: 1496 * unit - (IN) unit number 1497 * pid - (IN) pid 1498 * Returns: 1499 * BCM_E_XXX 1500 */ 1501 STATIC int 1502 tas_gclt_entries_remap(int unit, bcm_cosq_tas_profile_id_t pid) 1503 { 1504 tas_profile_ctrl_t *tp = NULL; 1505 bcm_cosq_tas_entry_t *hw_entries; 1506 int num_hw_entries; 1507 int rv = BCM_E_UNAVAIL; 1508 1509 BCM_IF_ERROR_RETURN(tas_profile_ctrl_get(unit, pid, &tp)); 1510 1511 rv = bcmi_tas_profile_entries_remap(unit, tp->port, 1512 tp->num_user_entries, 1513 tp->user_entries, 1514 &num_hw_entries, 1515 &hw_entries); 1516 if (BCM_FAILURE(rv)) { 1517 return rv; 1518 } 1519 1520 tp->num_hw_entries = num_hw_entries; 1521 tp->hw_entries = hw_entries; 1522 1523 return rv; 1524 } 1525 1526 /* 1527 * Function: 1528 * tas_profile_commit_validate 1529 * Purpose: 1530 * Function to do below validation before commit the profile 1531 * 1) Check HW configure (TAS enable? PTP mode/locked? ) 1532 * 2) Do entry remap according to the soc property 1533 * 3) Check pid status(resource) 1534 * Parameters: 1535 * unit - (IN) unit number 1536 * port - (IN) gport 1537 * tp - (IN) Internal profile structure 1538 * Returns: 1539 * BCM_E_XXX 1540 */ 1541 STATIC int 1542 tas_profile_commit_validate( 1543 int unit, 1544 bcm_gport_t port, tas_profile_ctrl_t *tp) 1545 { 1546 int tas_enable, ptp_mode, ptp_lock; 1547 int rv = BCM_E_NONE; 1548 1549 /* Check software resource is available */ 1550 if (tp->pstate != bcmCosqTASProfileInit) { 1551 LOG_ERROR(BSL_LS_BCM_TAS, 1552 (BSL_META_U(unit, "Unable to commit profile in state %s\n"), 1553 pstate_string[tp->pstate])); 1554 return BCM_E_CONFIG; 1555 } 1556 1557 /* Check tas enable */ 1558 BCM_IF_ERROR_RETURN( 1559 bcmi_esw_tas_control_get(unit, port, bcmCosqTASControlTASEnable, 1560 &tas_enable)); 1561 1562 /* check ptp_mode and ptp_lock */ 1563 BCM_IF_ERROR_RETURN( 1564 bcmi_esw_tas_control_get(unit, port, bcmCosqTASControlUsePTPTime, 1565 &ptp_mode)); 1566 BCM_IF_ERROR_RETURN( 1567 bcmi_esw_tas_control_get(unit, -1, bcmCosqTASControlTASPTPLock, 1568 &ptp_lock)); 1569 if (ptp_mode) { 1570 if (!ptp_lock) { 1571 LOG_ERROR(BSL_LS_BCM_TAS, 1572 (BSL_META_U(unit, "PTP need to be locked to run " 1573 "PTP mode.\n"))); 1574 return BCM_E_CONFIG; 1575 } 1576 /* 1577 * Need to validate basetime compare against currnt time 1578 * when GateEnable = TRUE 1579 */ 1580 if (tas_enable) { 1581 const tas_drv_t *td; 1582 bcmi_esw_tas_control_t *tc = NULL; 1583 1584 BCM_IF_ERROR_RETURN(tas_control_get(unit, &tc)); 1585 td = tc->tas_drvs; 1586 rv = BCM_E_NONE; 1587 if (td->tas_profile_basetime_check != NULL) { 1588 rv = td->tas_profile_basetime_check(unit, tp->base_time); 1589 } 1590 if (BCM_FAILURE(rv)) { 1591 return rv; 1592 } 1593 } 1594 } else { 1595 /* For non-PTP mode tas has to be enabled */ 1596 if (!tas_enable) { 1597 LOG_ERROR(BSL_LS_BCM_TAS, 1598 (BSL_META_U(unit, "TAS is not enabled !!\n"))); 1599 return BCM_E_DISABLED; 1600 } 1601 } 1602 /* 1603 * Prepare the HW profile(gclt) entries 1604 * Allocate hw ertries resource. And do entry remap if requested 1605 * from soc property. 1606 */ 1607 BCM_IF_ERROR_RETURN( 1608 tas_gclt_entries_remap(unit, tp->pid)); 1609 1610 return BCM_E_NONE; 1611 } 1612 1613 /* 1614 * Function: 1615 * bcmi_tas_profile_event_notify 1616 * Purpose: 1617 * Notified by chip tas interrupt handler 1618 * 1619 * Or notified when TAS is disabled to update the profile state. 1620 * active -> expired, commit/pending -> error 1621 * Parameters: 1622 * unit - (IN) unit number 1623 * lport - (IN) logical port 1624 * enable - (IN) tas is enable or disabled 1625 * Returns: 1626 * BCM_E_XXX 1627 */ 1628 STATIC int 1629 bcmi_tas_profile_event_notify( 1630 int unit, 1631 bcm_port_t lport, 1632 bcmi_tas_profile_event_type_t event) 1633 { 1634 bcmi_esw_tas_control_t *tc = NULL; 1635 bcm_cosq_tas_profile_id_t active_pid, process_pid; 1636 tas_profile_ctrl_t *tp_pending = NULL; 1637 tas_profile_ctrl_t *tp_active = NULL; 1638 int rv; 1639 1640 BCM_IF_ERROR_RETURN(tas_control_get(unit, &tc)); 1641 1642 TAS_LOCK(tc); 1643 active_pid = tc->active_pid[lport]; 1644 process_pid = tc->process_pid[lport]; 1645 TAS_UNLOCK(tc); 1646 if (active_pid) { 1647 rv = tas_profile_ctrl_get(unit, active_pid, &tp_active); 1648 if (BCM_FAILURE(rv)) { 1649 TAS_UNLOCK(tc); 1650 return rv; 1651 } 1652 } 1653 if (process_pid) { 1654 rv = tas_profile_ctrl_get(unit, process_pid, &tp_pending); 1655 if (BCM_FAILURE(rv)) { 1656 TAS_UNLOCK(tc); 1657 return rv; 1658 } 1659 } 1660 1661 switch (event) { 1662 case bcmiTASProfileEventProfileChange: 1663 /* Must have the valid process_pid */ 1664 if (!process_pid) { 1665 return BCM_E_INTERNAL; 1666 } 1667 TAS_PROFILE_LOCK(tp_pending); 1668 tp_pending->pstate = bcmCosqTASProfileActive; 1669 TAS_PROFILE_UNLOCK(tp_pending); 1670 if (active_pid) { 1671 TAS_PROFILE_LOCK(tp_active); 1672 tp_active->pstate = bcmCosqTASProfileExpired; 1673 tp_active->hw_index = -1; 1674 TAS_PROFILE_UNLOCK(tp_active); 1675 } 1676 TAS_LOCK(tc); 1677 tc->active_pid[lport] = process_pid; 1678 tc->process_pid[lport] = 0; 1679 TAS_UNLOCK(tc); 1680 break; 1681 case bcmiTASProfileEventBaseTimeErr: 1682 /* HW detects that the base time for new scheduler is already passed. 1683 * It'll abort the change command and continue the old schedule. 1684 * So keep the active pid, update the pending pid to error state. 1685 * Must have the valid process_pid 1686 */ 1687 if (!process_pid) { 1688 return BCM_E_INTERNAL; 1689 } 1690 TAS_PROFILE_LOCK(tp_pending); 1691 tp_pending->pstate = bcmCosqTASProfileError; 1692 tp_pending->hw_index = -1; 1693 TAS_PROFILE_UNLOCK(tp_pending); 1694 TAS_LOCK(tc); 1695 tc->process_pid[lport] = 0; 1696 TAS_UNLOCK(tc); 1697 break; 1698 case bcmiTASProfileEventNextCycleTimeErr: 1699 /* HW detects the next cycle start time is passed. 1700 * It'll go back to ERR_GATE_STATE after finish the current cycle. 1701 * So update the active to error. 1702 */ 1703 case bcmiTASProfileEventECCErr: 1704 /* HW detect that 2-bit ecc error when read the GCLT. 1705 * It'll stop execute GCLT and back to ERR_GATE_STATE. 1706 */ 1707 case bcmiTASProfileEventPtrErr: 1708 /* HW detect the read pointer over the GCLT size. 1709 * It'll stop execute GCLT and back to ERR_GATE_STATE. 1710 * Above cases must have the valid active_pid 1711 */ 1712 if (!active_pid) { 1713 return BCM_E_INTERNAL; 1714 } 1715 TAS_PROFILE_LOCK(tp_active); 1716 tp_active->pstate = bcmCosqTASProfileError; 1717 tp_active->hw_index = -1; 1718 TAS_PROFILE_UNLOCK(tp_active); 1719 TAS_LOCK(tc); 1720 tc->active_pid[lport] = 0; 1721 TAS_UNLOCK(tc); 1722 break; 1723 case bcmiTASProfileEventTASDisable: 1724 /* Software prgrame the TAS disable via bcm_cosq_tas_control_set. */ 1725 if (process_pid) { 1726 TAS_PROFILE_LOCK(tp_pending); 1727 tp_pending->pstate = bcmCosqTASProfileError; 1728 tp_pending->hw_index = -1; 1729 TAS_PROFILE_UNLOCK(tp_pending); 1730 } 1731 if (active_pid) { 1732 TAS_PROFILE_LOCK(tp_active); 1733 tp_active->pstate = bcmCosqTASProfileExpired; 1734 tp_active->hw_index = -1; 1735 TAS_PROFILE_UNLOCK(tp_active); 1736 } 1737 TAS_LOCK(tc); 1738 tc->active_pid[lport] = 0; 1739 tc->process_pid[lport] = 0; 1740 TAS_UNLOCK(tc); 1741 break; 1742 default: 1743 break; 1744 } 1745 1746 LOG_DEBUG(BSL_LS_BCM_TAS, 1747 (BSL_META_UP(unit, lport, 1748 "tas_profile_event_notify profile_event %d \n" 1749 "Active profile(pid 0x%08x) state = %s \n" 1750 "Pending profile (pid 0x%08x) state = %s \n"), 1751 event, active_pid, 1752 active_pid ? pstate_string[tp_active->pstate] : "N/A", 1753 process_pid, 1754 process_pid ? pstate_string[tp_pending->pstate] : "N/A")); 1755 return BCM_E_NONE; 1756 } 1757 1758 /* 1759 * Function: 1760 * bcmi_tas_commit_callback 1761 * Purpose: 1762 * The callback function to notify the information (config_change_time) of 1763 * the scheduled commit-profile. 1764 * The profile status will be updated accordingly. 1765 * Parameters: 1766 * unit - (IN) unit number 1767 * lport - (IN) logical port 1768 * config_change_time - (IN) config change time 1769 * fn_data - (IN) user data 1770 * Returns: 1771 * BCM_E_XXX 1772 */ 1773 STATIC int 1774 bcmi_tas_commit_callback( 1775 int unit, 1776 bcm_port_t lport, 1777 bcm_ptp_timestamp_t config_change_time, 1778 void *fn_data) 1779 { 1780 bcm_cosq_tas_profile_id_t pid; 1781 bcmi_esw_tas_control_t *tc = NULL; 1782 tas_profile_ctrl_t *tp = NULL; 1783 int rv; 1784 1785 BCM_IF_ERROR_RETURN(tas_control_get(unit, &tc)); 1786 TAS_LOCK(tc); 1787 pid = tc->process_pid[lport]; 1788 TAS_UNLOCK(tc); 1789 if (!pid) { 1790 LOG_DEBUG(BSL_LS_BCM_TAS, 1791 (BSL_META_UP(unit, lport, 1792 "The commit profile pid is dismissed !"))); 1793 return BCM_E_INTERNAL; 1794 } 1795 rv = tas_profile_ctrl_get(unit, pid, &tp); 1796 if (BCM_FAILURE(rv)) { 1797 TAS_UNLOCK(tc); 1798 return rv; 1799 } 1800 TAS_PROFILE_LOCK(tp); 1801 sal_memcpy(&tp->config_change_time, &config_change_time, 1802 sizeof(bcm_ptp_timestamp_t)); 1803 tp->pstate = bcmCosqTASProfilePending; 1804 TAS_PROFILE_UNLOCK(tp); 1805 LOG_DEBUG(BSL_LS_BCM_TAS, 1806 (BSL_META_UP(unit, lport, 1807 "bcmi_tas_commit_callback pid 0x%08x state %s\n"), 1808 pid, pstate_string[tp->pstate])); 1809 1810 return BCM_E_NONE; 1811 } 1812 1813 /* 1814 * Function: 1815 * tas_profile_schedule 1816 * Purpose: 1817 * Schedule the process to handle the committed profile. 1818 * For PTP mode, invoke the device specific schedule function to handle the 1819 * the device progamming constrain on time configurations. 1820 * For non-PTP mode, invoke the 'profile change' function. 1821 * Parameters: 1822 * unit - (IN) unit number 1823 * tp - (IN) internal profile 1824 * Returns: 1825 * BCM_E_XXX 1826 */ 1827 STATIC int 1828 tas_profile_schedule(int unit, tas_profile_ctrl_t *tp) 1829 { 1830 int rv = BCM_E_UNAVAIL; 1831 1832 if (tp->cycle_time) { 1833 rv = bcmi_tas_profile_schedule_config(unit, tp->port, tp->base_time, 1834 tp->cycle_time, 1835 tp->cycle_extension, 1836 bcmi_tas_commit_callback, 1837 NULL); 1838 if (BCM_FAILURE(rv)) { 1839 return rv; 1840 } 1841 } else { 1842 /* Issue config change */ 1843 rv = bcmi_tas_profile_change(unit, tp->port); 1844 if (BCM_FAILURE(rv)) { 1845 LOG_ERROR(BSL_LS_BCM_TAS, 1846 (BSL_META_UP(unit, tp->port, 1847 "Fail to issue config change !!\n"))); 1848 tp->pstate = bcmCosqTASProfileError; 1849 tp->hw_index = -1; 1850 return rv; 1851 } 1852 tp->pstate = bcmCosqTASProfilePending; 1853 } 1854 1855 return rv; 1856 } 1857 1858 /* 1859 * Function: 1860 * tas_profile_commit 1861 * Purpose: 1862 * Program the GCLT only. 1863 * Config change and time releated configuration are not in this function. 1864 * Parameters: 1865 * unit - (IN) unit number 1866 * tp - (IN) Internal profile structure 1867 * Returns: 1868 * BCM_E_XXX 1869 */ 1870 STATIC int 1871 tas_profile_commit(int unit, tas_profile_ctrl_t *tp) 1872 { 1873 int config_idx; 1874 int rv = BCM_E_NONE; 1875 1876 rv = bcmi_tas_profile_idx_get(unit, tp->port, &config_idx); 1877 if (BCM_FAILURE(rv)) { 1878 return rv; 1879 } 1880 rv = bcmi_tas_profile_entries_write(unit, tp->port, config_idx, 1881 tp->hw_entries, tp->num_hw_entries); 1882 if (BCM_FAILURE(rv)) { 1883 return rv; 1884 } 1885 1886 tp->pstate = bcmCosqTASProfileCommitted; 1887 tp->hw_index = config_idx; 1888 1889 return BCM_E_NONE; 1890 } 1891 1892 /* 1893 * Function: 1894 * tas_profile_get 1895 * Purpose: 1896 * Helper function for bcmi_esw_tas_profile_get. 1897 * Get the bcm profile information from internal profile. 1898 * Parameters: 1899 * unit - (IN) unit number 1900 * tp - (IN) internal profile 1901 * profile - (OUT) bcm profile 1902 * Returns: 1903 * BCM_E_XXX 1904 */ 1905 STATIC int 1906 tas_profile_get( 1907 int unit, 1908 tas_profile_ctrl_t *tp, 1909 bcm_cosq_tas_profile_t *profile) 1910 { 1911 if (profile == NULL) { 1912 return BCM_E_PARAM; 1913 } 1914 bcm_cosq_tas_profile_t_init(profile); 1915 profile->num_entries = tp->num_user_entries; 1916 sal_memcpy(&profile->entries, tp->user_entries, 1917 tp->num_user_entries * sizeof(bcm_cosq_tas_entry_t)); 1918 sal_memcpy(&profile->ptp_base_time, &tp->base_time, 1919 sizeof(bcm_ptp_timestamp_t)); 1920 profile->ptp_cycle_time = tp->cycle_time; 1921 profile->ptp_max_cycle_extension = tp->cycle_extension; 1922 1923 return BCM_E_NONE; 1924 } 1925 1926 /* 1927 * Function: 1928 * tas_profile_set 1929 * Purpose: 1930 * Helper function for bcmi_esw_tas_profile_set 1931 * Configure the internal profile database(specified via pid) according to 1932 * user configured bcm profile information. 1933 * Parameters: 1934 * unit - (IN) unit number 1935 * tp - (IN) internal profile 1936 * profile - (IN) bcm profile 1937 * Returns: 1938 * BCM_E_XXX 1939 */ 1940 STATIC int 1941 tas_profile_set( 1942 int unit, 1943 tas_profile_ctrl_t *tp, 1944 bcm_cosq_tas_profile_t *profile) 1945 { 1946 int rv; 1947 1948 /* Check the profile state */ 1949 if ((tp->pstate == bcmCosqTASProfileCommitted) || 1950 (tp->pstate == bcmCosqTASProfilePending) || 1951 (tp->pstate == bcmCosqTASProfileActive)) { 1952 LOG_ERROR(BSL_LS_BCM_TAS, 1953 (BSL_META_UP(unit, tp->port, "Unable to set profile in state " 1954 "%s\n"), pstate_string[tp->pstate])); 1955 return BCM_E_CONFIG; 1956 } 1957 1958 if (profile->num_entries != tp->num_user_entries) { 1959 TAS_FREE(unit, tp->user_entries, 0); 1960 tp->user_entries = NULL; 1961 TAS_ALLOC(unit, tp->user_entries, bcm_cosq_tas_entry_t, 1962 sizeof(bcm_cosq_tas_entry_t) * profile->num_entries, 1963 "tas profile entries", 0, rv); 1964 if (BCM_FAILURE(rv)) { 1965 return rv; 1966 } 1967 } 1968 1969 tp->pstate = bcmCosqTASProfileInit; 1970 tp->num_user_entries = profile->num_entries; 1971 /* copy valid profile->entries to tp->user_entries */ 1972 sal_memcpy(tp->user_entries, profile->entries, 1973 sizeof(bcm_cosq_tas_entry_t) * profile->num_entries); 1974 sal_memcpy(&tp->base_time, &profile->ptp_base_time, 1975 sizeof(bcm_ptp_timestamp_t)); 1976 1977 tp->cycle_time = profile->ptp_cycle_time; 1978 tp->cycle_extension = profile->ptp_max_cycle_extension; 1979 1980 return BCM_E_NONE; 1981 } 1982 1983 /* 1984 * Function: 1985 * tas_profile_destroy 1986 * Purpose: 1987 * Helper function for bcmi_esw_tas_profile_destroy. 1988 * Destroy and free the resource of the internal profile. 1989 * Parameters: 1990 * unit - (IN) unit number 1991 * tp - (IN) internal profile 1992 * Returns: 1993 * BCM_E_XXX 1994 */ 1995 STATIC int 1996 tas_profile_destroy(int unit, tas_profile_ctrl_t *tp) 1997 { 1998 TAS_PROFILE_LOCK(tp); 1999 if ((tp->pstate == bcmCosqTASProfileCommitted) || 2000 (tp->pstate == bcmCosqTASProfilePending) || 2001 (tp->pstate == bcmCosqTASProfileActive)) { 2002 LOG_ERROR(BSL_LS_BCM_TAS, 2003 (BSL_META_UP(unit, tp->port, "Unable to destroy profile in " 2004 "state %s\n"), 2005 pstate_string[tp->pstate])); 2006 TAS_PROFILE_UNLOCK(tp); 2007 return BCM_E_CONFIG; 2008 } 2009 2010 if (tp->user_entries) { 2011 TAS_FREE(unit, tp->user_entries, 0); 2012 tp->user_entries = NULL; 2013 } 2014 if (tp->hw_entries) { 2015 TAS_FREE(unit, tp->hw_entries, 0); 2016 tp->hw_entries = NULL; 2017 } 2018 TAS_PROFILE_UNLOCK(tp); 2019 if (tp->profile_mutex) { 2020 sal_mutex_destroy(tp->profile_mutex); 2021 tp->profile_mutex = NULL; 2022 } 2023 return BCM_E_NONE; 2024 } 2025 2026 /* 2027 * Function: 2028 * tas_profile_status_get 2029 * Purpose: 2030 * Helper function to get the profile status by specifing the pid. 2031 * Collect the bcm profile status from internal profile database. 2032 * Parameters: 2033 * unit - (IN) unit number 2034 * tp - (IN) internal profile 2035 * status - (OUT) profile status 2036 * Returns: 2037 * BCM_E_XXX 2038 */ 2039 STATIC int 2040 tas_profile_status_get( 2041 int unit, 2042 tas_profile_ctrl_t *tp, 2043 bcm_cosq_tas_profile_status_t *status) 2044 { 2045 if (status == NULL) { 2046 return BCM_E_PARAM; 2047 } 2048 bcm_cosq_tas_profile_status_t_init(status); 2049 status->profile_state = tp->pstate; 2050 status->num_entries = tp->num_hw_entries; 2051 if (status->num_entries > 0) { 2052 sal_memcpy(&status->entries, tp->hw_entries, 2053 tp->num_hw_entries * sizeof(bcm_cosq_tas_entry_t)); 2054 } 2055 2056 sal_memcpy(&status->config_change_time, &tp->config_change_time, 2057 sizeof(bcm_ptp_timestamp_t)); 2058 2059 return BCM_E_NONE; 2060 } 2061 2062 /* 2063 * Function: 2064 * bcmi_esw_tas_profile_create 2065 * Purpose: 2066 * Create a profile by specifying the profile settings including calendar 2067 * table, ptp time information for PTP mode. 2068 * A profile id will be assigned along with the settings. 2069 * Parameters: 2070 * unit - (IN) unit number 2071 * port - (IN) gport id 2072 * profile - (IN) Pointer to profile structure which specifies 2073 * entries in calendar table, ptp time information 2074 * for PTP mode 2075 * pid - (OUT) profile id 2076 * Returns: 2077 * BCM_E_XXX 2078 */ 2079 int 2080 bcmi_esw_tas_profile_create( 2081 int unit, 2082 bcm_gport_t port, 2083 bcm_cosq_tas_profile_t *profile, 2084 bcm_cosq_tas_profile_id_t *pid) 2085 { 2086 bcm_port_t lport; 2087 bcmi_esw_tas_control_t *tc = NULL; 2088 int rv; 2089 2090 if ((pid == NULL) || (profile == NULL)) { 2091 return BCM_E_PARAM; 2092 } 2093 2094 BCM_IF_ERROR_RETURN(tas_control_get(unit, &tc)); 2095 2096 /* parameter validate - port */ 2097 BCM_IF_ERROR_RETURN(tas_gport_validate(unit, port, &lport)); 2098 /* parameter validate - content of the profile structure */ 2099 rv = tas_profile_profile_param_validate(unit, port, profile); 2100 if (BCM_FAILURE(rv)) { 2101 return rv; 2102 } 2103 2104 /* Create the profile and get the profile id */ 2105 rv = tas_profile_create(unit, lport, profile, pid); 2106 2107 return rv; 2108 } 2109 2110 /* 2111 * Function: 2112 * bcmi_esw_tas_profile_commit 2113 * Purpose: 2114 * Commit the profile to indicate the profile is ready to write to hardware. 2115 * Parameters: 2116 * unit - (IN) unit number 2117 * port - (IN) gport id 2118 * pid - (IN) profile id 2119 * Returns: 2120 * BCM_E_XXX 2121 */ 2122 int 2123 bcmi_esw_tas_profile_commit( 2124 int unit, 2125 bcm_gport_t port, 2126 bcm_cosq_tas_profile_id_t pid) 2127 { 2128 bcmi_esw_tas_control_t *tc = NULL; 2129 int rv; 2130 bcm_port_t lport; 2131 tas_profile_ctrl_t *tp; 2132 2133 /* parameter validate - port and pid */ 2134 BCM_IF_ERROR_RETURN( 2135 tas_profile_id_validate(unit, port, pid, &lport)); 2136 BCM_IF_ERROR_RETURN(tas_control_get(unit, &tc)); 2137 TAS_LOCK(tc); 2138 /* Check hardware resource is available to do the commit. 2139 * Currently, only allow one profile in process (either commit or pending) 2140 * at one time. 2141 */ 2142 if (tc->process_pid[lport] != 0) { 2143 TAS_UNLOCK(tc); 2144 return BCM_E_RESOURCE; 2145 } 2146 tc->process_pid[lport] = pid; 2147 rv = tas_profile_ctrl_get(unit, pid, &tp); 2148 if (BCM_FAILURE(rv)) { 2149 TAS_UNLOCK(tc); 2150 return rv; 2151 } 2152 TAS_UNLOCK(tc); 2153 2154 TAS_PROFILE_LOCK(tp); 2155 rv = tas_profile_commit_validate(unit, port, tp); 2156 if (BCM_FAILURE(rv)) { 2157 tp->pstate = bcmCosqTASProfileError; 2158 TAS_PROFILE_UNLOCK(tp); 2159 TAS_LOCK(tc); 2160 tc->process_pid[lport] = 0; 2161 TAS_UNLOCK(tc); 2162 return rv; 2163 } 2164 2165 rv = tas_profile_commit(unit, tp); 2166 if (BCM_FAILURE(rv)) { 2167 tp->pstate = bcmCosqTASProfileError; 2168 TAS_PROFILE_UNLOCK(tp); 2169 TAS_LOCK(tc); 2170 tc->process_pid[lport] = 0; 2171 TAS_UNLOCK(tc); 2172 return rv; 2173 } 2174 2175 rv = tas_profile_schedule(unit, tp); 2176 if (BCM_FAILURE(rv)) { 2177 tp->pstate = bcmCosqTASProfileError; 2178 TAS_PROFILE_UNLOCK(tp); 2179 TAS_LOCK(tc); 2180 tc->process_pid[lport] = 0; 2181 TAS_UNLOCK(tc); 2182 return rv; 2183 } 2184 2185 TAS_PROFILE_UNLOCK(tp); 2186 return rv; 2187 } 2188 2189 /* 2190 * Function: 2191 * bcmi_esw_tas_profile_destroy 2192 * Purpose: 2193 * Destroy the profile and associated resources. 2194 * Parameters: 2195 * unit - (IN) unit number 2196 * port - (IN) gport id 2197 * pid - (IN) profile id 2198 * Returns: 2199 * BCM_E_XXX 2200 */ 2201 int 2202 bcmi_esw_tas_profile_destroy( 2203 int unit, 2204 bcm_gport_t port, 2205 bcm_cosq_tas_profile_id_t pid) 2206 { 2207 bcm_port_t lport; 2208 tas_profile_ctrl_t *tp; 2209 bcmi_esw_tas_control_t *tc = NULL; 2210 2211 BCM_IF_ERROR_RETURN( 2212 tas_profile_id_validate(unit, port, pid, &lport)); 2213 2214 BCM_IF_ERROR_RETURN(tas_profile_ctrl_get(unit, pid, &tp)); 2215 BCM_IF_ERROR_RETURN(tas_profile_destroy(unit, tp)); 2216 2217 BCM_IF_ERROR_RETURN(tas_control_get(unit, &tc)); 2218 2219 TAS_LOCK(tc); 2220 TAS_PROFILE_REMOVE(tc->profile_list, tas_profile_ctrl_t, tp, lport); 2221 TAS_FREE(unit, tp, 0); 2222 TAS_UNLOCK(tc); 2223 2224 return BCM_E_NONE; 2225 } 2226 2227 /* 2228 * Function: 2229 * bcmi_esw_tas_profile_destroy_all 2230 * Purpose: 2231 * Destroy all the profile associated with the port. 2232 * Parameters: 2233 * unit - (IN) unit number 2234 * port - (IN) gport 2235 * Returns: 2236 * BCM_E_XXX 2237 */ 2238 int 2239 bcmi_esw_tas_profile_destroy_all( 2240 int unit, 2241 bcm_gport_t port) 2242 { 2243 bcm_port_t lport; 2244 bcmi_esw_tas_control_t *tc = NULL; 2245 tas_profile_ctrl_t *tp; 2246 int rv = BCM_E_NONE; 2247 2248 BCM_IF_ERROR_RETURN(tas_gport_validate(unit, port, &lport)); 2249 BCM_IF_ERROR_RETURN(tas_control_get(unit, &tc)); 2250 TAS_LOCK(tc); 2251 TAS_PROFILE_ITER(tc->profile_list, tp, lport) { 2252 TAS_PROFILE_LOCK(tp); 2253 rv = tas_profile_destroy(unit, tp); 2254 if (BCM_FAILURE(rv)) { 2255 TAS_PROFILE_UNLOCK(tp); 2256 TAS_UNLOCK(tc); 2257 return rv; 2258 } 2259 TAS_PROFILE_REMOVE(tc->profile_list, tas_profile_ctrl_t, tp, lport); 2260 TAS_PROFILE_UNLOCK(tp); 2261 TAS_FREE(unit, tp, 0); 2262 } 2263 2264 TAS_UNLOCK(tc); 2265 return rv; 2266 } 2267 2268 /* 2269 * Function: 2270 * bcmi_esw_tas_profile_get 2271 * Purpose: 2272 * Get the profile information by specifying the profile id. 2273 * Parameters: 2274 * unit - (IN) unit number 2275 * port - (IN) gport id 2276 * pid - (IN) profile id 2277 * profile - (OUT) pointer to profile structure 2278 * Returns: 2279 * BCM_E_XXX 2280 */ 2281 int 2282 bcmi_esw_tas_profile_get( 2283 int unit, 2284 bcm_gport_t port, 2285 bcm_cosq_tas_profile_id_t pid, 2286 bcm_cosq_tas_profile_t *profile) 2287 { 2288 tas_profile_ctrl_t *tp; 2289 int rv; 2290 2291 if (profile == NULL) { 2292 return BCM_E_PARAM; 2293 } 2294 BCM_IF_ERROR_RETURN( 2295 tas_profile_id_validate(unit, port, pid, NULL)); 2296 BCM_IF_ERROR_RETURN(tas_profile_ctrl_get(unit, pid, &tp)); 2297 TAS_PROFILE_LOCK(tp); 2298 rv = tas_profile_get(unit, tp, profile); 2299 TAS_PROFILE_UNLOCK(tp); 2300 return rv; 2301 } 2302 2303 /* 2304 * Function: 2305 * bcmi_esw_tas_profile_set 2306 * Purpose: 2307 * Modify the profile information 2308 * Parameters: 2309 * unit - (IN) unit number 2310 * port - (IN) gport id 2311 * pid - (IN) profile id 2312 * profile - (IN) pointer to profile structure 2313 * Returns: 2314 * BCM_E_XXX 2315 */ 2316 int 2317 bcmi_esw_tas_profile_set( 2318 int unit, 2319 bcm_gport_t port, 2320 bcm_cosq_tas_profile_id_t pid, 2321 bcm_cosq_tas_profile_t *profile) 2322 { 2323 tas_profile_ctrl_t *tp = NULL; 2324 int rv; 2325 2326 if (profile == NULL) { 2327 return BCM_E_PARAM; 2328 } 2329 BCM_IF_ERROR_RETURN( 2330 tas_profile_id_validate(unit, port, pid, NULL)); 2331 BCM_IF_ERROR_RETURN( 2332 tas_profile_profile_param_validate(unit, port, profile)); 2333 2334 BCM_IF_ERROR_RETURN(tas_profile_ctrl_get(unit, pid, &tp)); 2335 TAS_PROFILE_LOCK(tp); 2336 rv = tas_profile_set(unit, tp, profile); 2337 TAS_PROFILE_UNLOCK(tp); 2338 return rv; 2339 } 2340 2341 /* 2342 * Function: 2343 * bcmi_esw_tas_profile_traverse 2344 * Purpose: 2345 * Traverse the set of profiles associated with the specified port. 2346 * Parameters: 2347 * unit - (IN) unit number 2348 * port - (IN) gport id 2349 * cb - (IN) A pointer to callback function to call 2350 * for each profile in the specified gport. 2351 * user_data - (IN) Pointer to user data to supply in the callback 2352 * Returns: 2353 * BCM_E_XXX 2354 */ 2355 int 2356 bcmi_esw_tas_profile_traverse( 2357 int unit, 2358 bcm_gport_t port, 2359 bcm_cosq_tas_profile_traverse_cb cb, 2360 void *user_data) 2361 { 2362 bcmi_esw_tas_control_t *tc = NULL; 2363 tas_profile_ctrl_t *tp = NULL; 2364 bcm_port_t lport; 2365 int rv; 2366 2367 if (cb == NULL) { 2368 return BCM_E_PARAM; 2369 } 2370 BCM_IF_ERROR_RETURN(tas_gport_validate(unit, port, &lport)); 2371 BCM_IF_ERROR_RETURN(tas_control_get(unit, &tc)); 2372 TAS_LOCK(tc); 2373 TAS_PROFILE_ITER(tc->profile_list, tp, lport) { 2374 TAS_PROFILE_LOCK(tp); 2375 rv = cb(unit, port, tp->pid, user_data); 2376 if (BCM_FAILURE(rv)) { 2377 LOG_ERROR(BSL_LS_BCM_TAS, 2378 (BSL_META_UP(unit, lport, "Error on user call back with " 2379 "pid 0x%x \n"), tp->pid)); 2380 TAS_PROFILE_UNLOCK(tp); 2381 TAS_UNLOCK(tc); 2382 return rv; 2383 } 2384 TAS_PROFILE_UNLOCK(tp); 2385 } 2386 TAS_UNLOCK(tc); 2387 return BCM_E_NONE; 2388 } 2389 2390 /* 2391 * Function: 2392 * bcmi_esw_tas_profile_status_get 2393 * Purpose: 2394 * Get the profile status like profile state, config change time and 2395 * entries in the hardware calendar table. 2396 * Parameters: 2397 * unit - (IN) unit number 2398 * port - (IN) gport id 2399 * pid - (IN) profile id 2400 * status - (OUT) pointer to profile status structure 2401 * Returns: 2402 * BCM_E_XXX 2403 */ 2404 int 2405 bcmi_esw_tas_profile_status_get( 2406 int unit, 2407 bcm_gport_t port, 2408 bcm_cosq_tas_profile_id_t pid, 2409 bcm_cosq_tas_profile_status_t *status) 2410 { 2411 int rv; 2412 tas_profile_ctrl_t *tp = NULL; 2413 2414 BCM_IF_ERROR_RETURN( 2415 tas_profile_id_validate(unit, port, pid, NULL)); 2416 BCM_IF_ERROR_RETURN(tas_profile_ctrl_get(unit, pid, &tp)); 2417 TAS_PROFILE_LOCK(tp); 2418 rv = tas_profile_status_get(unit, tp, status); 2419 TAS_PROFILE_UNLOCK(tp); 2420 return rv; 2421 } 2422 2423 /* 2424 * Function: 2425 * tas_profile_destroy_all 2426 * Purpose: 2427 * Helper function for bcmi_esw_tas_profile_destroy_all. 2428 * Destroy all allocated resource of the profiles on specified port. 2429 * Parameters: 2430 * unit - (IN) unit number 2431 * lport - (IN) logical port 2432 * Returns: 2433 * BCM_E_XXX 2434 */ 2435 STATIC int 2436 tas_profile_destroy_all(int unit, bcm_port_t lport) 2437 { 2438 bcmi_esw_tas_control_t *tc = NULL; 2439 tas_profile_ctrl_t *tp = NULL; 2440 2441 BCM_IF_ERROR_RETURN(tas_control_get(unit, &tc)); 2442 2443 if (tc->profile_list_count <= lport) { 2444 return BCM_E_NONE; 2445 } 2446 TAS_PROFILE_ITER(tc->profile_list, tp, lport) { 2447 if (tp->user_entries) { 2448 TAS_FREE(unit, tp->user_entries, 0); 2449 tp->user_entries = NULL; 2450 } 2451 if (tp->hw_entries) { 2452 TAS_FREE(unit, tp->hw_entries, 0); 2453 tp->hw_entries = NULL; 2454 } 2455 if (tp->profile_mutex) { 2456 sal_mutex_destroy(tp->profile_mutex); 2457 tp->profile_mutex = NULL; 2458 } 2459 } 2460 TAS_PROFILE_REMOVE_ALL(tc->profile_list, tas_profile_ctrl_t, lport); 2461 2462 return BCM_E_NONE; 2463 } 2464 2465 /* 2466 * Function: 2467 * bcmi_esw_tas_cleanup 2468 * Purpose: 2469 * Internal function to clear the resource of the tas module. 2470 * Parameters: 2471 * unit - (IN) unit number 2472 * Returns: 2473 * BCM_E_XXX 2474 */ 2475 int 2476 bcmi_esw_tas_cleanup(int unit) 2477 { 2478 bcmi_esw_tas_control_t *tc = NULL; 2479 bcm_port_t port; 2480 int rv; 2481 2482 if (tas_control[unit] != NULL) { 2483 tc = tas_control[unit]; 2484 if (tc->profile_list) { 2485 PBMP_ALL_ITER(unit, port) { 2486 rv = tas_profile_destroy_all(unit, port); 2487 if (BCM_FAILURE (rv)) { 2488 return rv; 2489 } 2490 } 2491 } 2492 if (tc->active_pid) { 2493 TAS_FREE(unit, tc->active_pid, 0); 2494 tc->active_pid = NULL; 2495 } 2496 if (tc->process_pid) { 2497 TAS_FREE(unit, tc->process_pid, 0); 2498 tc->process_pid = NULL; 2499 } 2500 if (tc->tas_properties) { 2501 TAS_FREE(unit, tc->tas_properties, 0); 2502 tc->tas_properties = NULL; 2503 } 2504 if (tc->tas_mutex != NULL) { 2505 sal_mutex_destroy(tc->tas_mutex); 2506 tc->tas_mutex = NULL; 2507 } 2508 TAS_FREE(unit, tc, 0); 2509 tas_control[unit] = NULL; 2510 } 2511 return BCM_E_NONE; 2512 } 2513 2514 /* 2515 * Function: 2516 * bcmi_esw_tas_deinit 2517 * Purpose: 2518 * Internal function to free the resource of the tas module. 2519 * Parameters: 2520 * unit - (IN) unit number 2521 * Returns: 2522 * BCM_E_XXX 2523 */ 2524 int 2525 bcmi_esw_tas_deinit(int unit) 2526 { 2527 bcmi_esw_tas_control_t *tc = NULL; 2528 2529 BCM_IF_ERROR_RETURN(tas_control_get(unit, &tc)); 2530 2531 if (tc->tas_drvs) { 2532 const tas_drv_t *td = tc->tas_drvs; 2533 if (td->tas_profile_deinit != NULL) { 2534 BCM_IF_ERROR_RETURN(td->tas_profile_deinit(unit)); 2535 } 2536 } 2537 2538 return bcmi_esw_tas_cleanup(unit); 2539 } 2540 2541 2542 #ifdef BCM_WARM_BOOT_SUPPORT 2543 STATIC int 2544 bcmi_esw_tas_scache_alloc(int unit) 2545 { 2546 bcmi_esw_tas_control_t *tc = NULL; 2547 soc_scache_handle_t scache_handle; 2548 uint8 *scache_ptr; 2549 int alloc_size = 0; 2550 int profile_alloc_size = 0, profile_list_count; 2551 2552 BCM_IF_ERROR_RETURN(tas_control_get(unit, &tc)); 2553 TAS_LOCK(tc); 2554 profile_list_count = tc->profile_list_count; 2555 TAS_UNLOCK(tc); 2556 /* profile list count */ 2557 alloc_size += sizeof(int); 2558 /* pid */ 2559 profile_alloc_size += sizeof(bcm_cosq_tas_profile_id_t); 2560 /* pstate */ 2561 profile_alloc_size += sizeof(bcm_cosq_tas_profile_state_t); 2562 /* profile hw index */ 2563 profile_alloc_size += sizeof(int); 2564 /* user entries */ 2565 profile_alloc_size += sizeof(int); 2566 profile_alloc_size += sizeof(bcm_cosq_tas_entry_t) * 2567 BCM_COSQ_MAX_TAS_CALENDAR_TABLE_SIZE; 2568 /* hw entries */ 2569 profile_alloc_size += sizeof(int); 2570 profile_alloc_size += sizeof(bcm_cosq_tas_entry_t) * 2571 BCM_COSQ_MAX_TAS_CALENDAR_TABLE_SIZE; 2572 /* base time */ 2573 profile_alloc_size += sizeof(bcm_ptp_timestamp_t); 2574 /* config change time */ 2575 profile_alloc_size += sizeof(bcm_ptp_timestamp_t); 2576 /* cycle time */ 2577 profile_alloc_size += sizeof(uint32); 2578 /* cycle extension time */ 2579 profile_alloc_size += sizeof(uint32); 2580 2581 alloc_size += MAX_TAS_PROFILE_CNT * profile_alloc_size * 2582 profile_list_count; 2583 2584 /* profile cnt, active_pid, process_pid */ 2585 alloc_size += (sizeof(uint16) + sizeof(bcm_cosq_tas_profile_id_t) + 2586 sizeof(bcm_cosq_tas_profile_id_t)) * profile_list_count; 2587 2588 SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_COSQ, 2589 BCMI_COSQ_WB_SCACHE_PARTITION_TAS); 2590 BCM_IF_ERROR_RETURN( 2591 _bcm_esw_scache_ptr_get(unit, scache_handle, 1, alloc_size, 2592 &scache_ptr, BCMI_COSQ_WB_TAS_VERSION_1_0, 2593 NULL)); 2594 return BCM_E_NONE; 2595 } 2596 2597 int 2598 bcmi_esw_tas_sync(int unit) 2599 { 2600 bcmi_esw_tas_control_t *tc = NULL; 2601 tas_profile_ctrl_t *tp = NULL; 2602 soc_scache_handle_t scache_handle; 2603 uint8 *scache_ptr, *temp_ptr; 2604 int i; 2605 int rv; 2606 uint16 profile_cnt; /* profile count per index */ 2607 2608 SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_COSQ, 2609 BCMI_COSQ_WB_SCACHE_PARTITION_TAS); 2610 2611 rv = _bcm_esw_scache_ptr_get(unit, scache_handle, 0, 0, 2612 &scache_ptr, BCMI_COSQ_WB_TAS_VERSION_1_0, 2613 NULL); 2614 if (BCM_FAILURE(rv)) { 2615 LOG_ERROR(BSL_LS_BCM_TAS, 2616 (BSL_META_U(unit, "Fail to get Scahce ptr !\n"))); 2617 return rv; 2618 } 2619 BCM_IF_ERROR_RETURN(tas_control_get(unit, &tc)); 2620 TAS_LOCK(tc); 2621 /* store profile list count */ 2622 sal_memcpy(scache_ptr, &tc->profile_list_count, sizeof(int)); 2623 scache_ptr += sizeof(int); 2624 2625 for (i = 0; i < tc->profile_list_count; i++) { 2626 profile_cnt = 0; 2627 /* reserve the space for the profile_cnt */ 2628 temp_ptr = scache_ptr; 2629 scache_ptr += sizeof(uint16); 2630 TAS_PROFILE_ITER(tc->profile_list, tp, i) { 2631 /* store pid */ 2632 sal_memcpy(scache_ptr, &tp->pid, sizeof(bcm_cosq_tas_profile_id_t)); 2633 scache_ptr += sizeof(bcm_cosq_tas_profile_id_t); 2634 /* store profile state */ 2635 sal_memcpy(scache_ptr, &tp->pstate, 2636 sizeof(bcm_cosq_tas_profile_state_t)); 2637 scache_ptr += sizeof(bcm_cosq_tas_profile_state_t); 2638 /* store hw_index */ 2639 sal_memcpy(scache_ptr, &tp->hw_index, sizeof(int)); 2640 scache_ptr += sizeof(int); 2641 /* store num_user_entries */ 2642 sal_memcpy(scache_ptr, &tp->num_user_entries, sizeof(int)); 2643 scache_ptr += sizeof(int); 2644 /* store user entries */ 2645 sal_memcpy(scache_ptr, tp->user_entries, 2646 tp->num_user_entries * sizeof(bcm_cosq_tas_entry_t)); 2647 scache_ptr += tp->num_user_entries * sizeof(bcm_cosq_tas_entry_t); 2648 /* store num_hw_entries */ 2649 sal_memcpy(scache_ptr, &tp->num_hw_entries, sizeof(int)); 2650 scache_ptr += sizeof(int); 2651 if (tp->num_hw_entries) { 2652 /* store hw entries */ 2653 sal_memcpy(scache_ptr, tp->hw_entries, 2654 tp->num_hw_entries * sizeof(bcm_cosq_tas_entry_t)); 2655 scache_ptr += tp->num_hw_entries * sizeof(bcm_cosq_tas_entry_t); 2656 } 2657 /* store base_time */ 2658 sal_memcpy(scache_ptr, &tp->base_time, sizeof(bcm_ptp_timestamp_t)); 2659 scache_ptr += sizeof(bcm_ptp_timestamp_t); 2660 /* store config_change_time */ 2661 sal_memcpy(scache_ptr, &tp->config_change_time, 2662 sizeof(bcm_ptp_timestamp_t)); 2663 scache_ptr += sizeof(bcm_ptp_timestamp_t); 2664 /* store cycle_time */ 2665 sal_memcpy(scache_ptr, &tp->cycle_time, sizeof(uint32)); 2666 scache_ptr += sizeof(uint32); 2667 /* store cycle_extension */ 2668 sal_memcpy(scache_ptr, &tp->cycle_extension, sizeof(uint32)); 2669 scache_ptr += sizeof(uint32); 2670 profile_cnt++; 2671 } 2672 /* store the profile_cnt to the reseved ptr */ 2673 sal_memcpy(temp_ptr, &profile_cnt, sizeof(uint16)); 2674 2675 /* store active_pid */ 2676 sal_memcpy(scache_ptr, &tc->active_pid[i], 2677 sizeof(bcm_cosq_tas_profile_id_t)); 2678 scache_ptr += sizeof(bcm_cosq_tas_profile_id_t); 2679 /* store process_pid */ 2680 sal_memcpy(scache_ptr, &tc->process_pid[i], 2681 sizeof(bcm_cosq_tas_profile_id_t)); 2682 scache_ptr += sizeof(bcm_cosq_tas_profile_id_t); 2683 } 2684 TAS_UNLOCK(tc); 2685 return BCM_E_NONE; 2686 } 2687 2688 STATIC int 2689 bcmi_esw_tas_recover(int unit, uint8 *scache_ptr) 2690 { 2691 bcmi_esw_tas_control_t *tc = NULL; 2692 tas_profile_ctrl_t *tp = NULL; 2693 int i, j; 2694 uint16 profile_cnt; 2695 int rv = BCM_E_NONE; 2696 2697 BCM_IF_ERROR_RETURN(tas_control_get(unit, &tc)); 2698 TAS_LOCK(tc); 2699 sal_memcpy(&tc->profile_list_count, scache_ptr, sizeof(int)); 2700 scache_ptr += sizeof(int); 2701 2702 for (i = 0; i < tc->profile_list_count; i++) { 2703 sal_memcpy(&profile_cnt, scache_ptr, sizeof(uint16)); 2704 scache_ptr += sizeof(uint16); 2705 2706 for (j = 0; j < profile_cnt; j ++) { 2707 tp = NULL; 2708 /* Allocate profile structure */ 2709 TAS_ALLOC(unit, tp, tas_profile_ctrl_t, 2710 sizeof(tas_profile_ctrl_t), 2711 "tas profile", 0, rv); 2712 if (BCM_FAILURE(rv)) { 2713 TAS_UNLOCK(tc); 2714 return rv; 2715 } 2716 /* Create profile lock */ 2717 tp->profile_mutex = sal_mutex_create("tas_profile.lock"); 2718 if (NULL == tp->profile_mutex) { 2719 TAS_FREE(unit, tp, 0); 2720 TAS_UNLOCK(tc); 2721 return BCM_E_RESOURCE; 2722 } 2723 /* restore port */ 2724 tp->port = i; 2725 /* restore pid */ 2726 sal_memcpy(&tp->pid, scache_ptr, sizeof(bcm_cosq_tas_profile_id_t)); 2727 scache_ptr += sizeof(bcm_cosq_tas_profile_id_t); 2728 /* restore profile state */ 2729 sal_memcpy(&tp->pstate, scache_ptr, 2730 sizeof(bcm_cosq_tas_profile_state_t)); 2731 scache_ptr += sizeof(bcm_cosq_tas_profile_state_t); 2732 /* restore hw_index */ 2733 sal_memcpy(&tp->hw_index, scache_ptr, sizeof(int)); 2734 scache_ptr += sizeof(int); 2735 /* restore num_user_entries */ 2736 sal_memcpy(&tp->num_user_entries, scache_ptr, sizeof(int)); 2737 scache_ptr += sizeof(int); 2738 /* Allocate tp->user_entries */ 2739 TAS_ALLOC(unit, tp->user_entries, bcm_cosq_tas_entry_t, 2740 sizeof(bcm_cosq_tas_entry_t) * tp->num_user_entries, 2741 "tas profile entries", 0, rv); 2742 if (BCM_FAILURE(rv)) { 2743 sal_mutex_destroy(tp->profile_mutex); 2744 TAS_FREE(unit, tp, 0); 2745 TAS_UNLOCK(tc); 2746 return rv; 2747 } 2748 /* restore user entries */ 2749 sal_memcpy(tp->user_entries, scache_ptr, 2750 tp->num_user_entries * sizeof(bcm_cosq_tas_entry_t)); 2751 scache_ptr += tp->num_user_entries * sizeof(bcm_cosq_tas_entry_t); 2752 /* restore num_hw_entries */ 2753 sal_memcpy(&tp->num_hw_entries, scache_ptr, sizeof(int)); 2754 scache_ptr += sizeof(int); 2755 if (tp->num_hw_entries) { 2756 /* Allocate tp->user_entries*/ 2757 TAS_ALLOC(unit, tp->hw_entries, bcm_cosq_tas_entry_t, 2758 sizeof(bcm_cosq_tas_entry_t) * tp->num_hw_entries, 2759 "tas profile entries", 0, rv); 2760 if (BCM_FAILURE(rv)) { 2761 TAS_FREE(unit, tp->user_entries, 0); 2762 tp->user_entries = NULL; 2763 sal_mutex_destroy(tp->profile_mutex); 2764 TAS_FREE(unit, tp, 0); 2765 TAS_UNLOCK(tc); 2766 return rv; 2767 } 2768 /* restore hw entries */ 2769 sal_memcpy(tp->hw_entries, scache_ptr, 2770 tp->num_hw_entries * sizeof(bcm_cosq_tas_entry_t)); 2771 scache_ptr += tp->num_hw_entries * sizeof(bcm_cosq_tas_entry_t); 2772 } 2773 /* restore base_time */ 2774 sal_memcpy(&tp->base_time, scache_ptr, sizeof(bcm_ptp_timestamp_t)); 2775 scache_ptr += sizeof(bcm_ptp_timestamp_t); 2776 /* restore config_change_time */ 2777 sal_memcpy(&tp->config_change_time, scache_ptr, 2778 sizeof(bcm_ptp_timestamp_t)); 2779 scache_ptr += sizeof(bcm_ptp_timestamp_t); 2780 /* restore cycle_time */ 2781 sal_memcpy(&tp->cycle_time, scache_ptr, sizeof(uint32)); 2782 scache_ptr += sizeof(uint32); 2783 /* restore cycle_extension */ 2784 sal_memcpy(&tp->cycle_extension, scache_ptr, sizeof(uint32)); 2785 scache_ptr += sizeof(uint32); 2786 /* Insert profile to tas profile set */ 2787 TAS_PROFILE_INSERT(tc->profile_list, tp, i); 2788 } 2789 /* store active_pid */ 2790 sal_memcpy(&tc->active_pid[i], scache_ptr, 2791 sizeof(bcm_cosq_tas_profile_id_t)); 2792 scache_ptr += sizeof(bcm_cosq_tas_profile_id_t); 2793 /* store process_pid */ 2794 sal_memcpy(&tc->process_pid[i], scache_ptr, 2795 sizeof(bcm_cosq_tas_profile_id_t)); 2796 scache_ptr += sizeof(bcm_cosq_tas_profile_id_t); 2797 } 2798 TAS_UNLOCK(tc); 2799 return BCM_E_NONE; 2800 } 2801 2802 /* The pending profile might become active during the warmboot 2803 * Update the profile state of the process_id and active_id. 2804 */ 2805 STATIC int 2806 bcmi_esw_tas_wb_profile_update(int unit) 2807 { 2808 bcmi_esw_tas_control_t *tc = NULL; 2809 tas_profile_ctrl_t *tp_active = NULL, *tp_process = NULL; 2810 int i, config_idx; 2811 bcm_cosq_tas_profile_id_t active_pid, process_pid; 2812 int rv; 2813 2814 BCM_IF_ERROR_RETURN(tas_control_get(unit, &tc)); 2815 TAS_LOCK(tc); 2816 for (i = 0; i < tc->profile_list_count; i++) { 2817 if (!BCM_PBMP_MEMBER(PBMP_PORT_ALL(unit), i)) { 2818 continue; 2819 } 2820 rv = bcmi_tas_profile_idx_get(unit, i, &config_idx); 2821 if (BCM_FAILURE(rv)) { 2822 TAS_UNLOCK(tc); 2823 return rv; 2824 } 2825 process_pid = tc->process_pid[i]; 2826 if (process_pid) { 2827 rv = tas_profile_ctrl_get(unit, tc->process_pid[i], &tp_process); 2828 if (BCM_FAILURE(rv)) { 2829 TAS_UNLOCK(tc); 2830 return rv; 2831 } 2832 if (tp_process->hw_index != -1) { 2833 if (tp_process->hw_index != config_idx) { 2834 /* 2835 * hw_index != config_idx means the process pid 2836 * become active. 2837 * Note: Config change time can not be recovered since 2838 * it happened after leaving SDK and before WARMBOOT. 2839 */ 2840 tp_process->pstate = bcmCosqTASProfileActive; 2841 2842 active_pid = tc->active_pid[i]; 2843 if (active_pid) { 2844 rv = tas_profile_ctrl_get(unit, tc->active_pid[i], 2845 &tp_active); 2846 if (BCM_FAILURE(rv)) { 2847 TAS_UNLOCK(tc); 2848 return rv; 2849 } 2850 tp_active->pstate = bcmCosqTASProfileExpired; 2851 tp_active->hw_index = -1; 2852 } 2853 tc->active_pid[i] = process_pid; 2854 tc->process_pid[i] = 0; 2855 } else { 2856 /* 2857 * Clean up the process pid profile state which was 2858 * committed but not schedule to HW yet. 2859 */ 2860 tp_process->pstate = bcmCosqTASProfileError; 2861 tp_process->hw_index = -1; 2862 tc->process_pid[i] = 0; 2863 } 2864 } 2865 } 2866 } 2867 TAS_UNLOCK(tc); 2868 2869 return BCM_E_NONE; 2870 } 2871 2872 int 2873 bcmi_esw_tas_reinit(int unit) 2874 { 2875 soc_scache_handle_t scache_handle; 2876 int stable_size; 2877 uint8 *tas_scache; 2878 bcm_ptp_timestamp_t current_time; 2879 2880 SOC_IF_ERROR_RETURN(soc_stable_size_get(unit, &stable_size)); 2881 2882 /* In case WARM BOOT level 2 store is not configured return from here. */ 2883 if (!SOC_WARM_BOOT_SCACHE_IS_LIMITED(unit) && (stable_size > 0)) { 2884 SOC_SCACHE_HANDLE_SET(scache_handle, unit, BCM_MODULE_COSQ, 2885 BCMI_COSQ_WB_SCACHE_PARTITION_TAS); 2886 BCM_IF_ERROR_RETURN( 2887 _bcm_esw_scache_ptr_get(unit, scache_handle, 0, 0, 2888 &tas_scache, BCMI_COSQ_WB_TAS_VERSION_1_0, 2889 NULL)); 2890 BCM_IF_ERROR_RETURN(bcmi_esw_tas_recover(unit, tas_scache)); 2891 BCM_IF_ERROR_RETURN(bcmi_esw_tas_wb_profile_update(unit)); 2892 } 2893 2894 if (soc_feature(unit, soc_feature_use_local_1588)) { 2895 /* Get currnet time to initiate the time interface id */ 2896 (void)bcmi_tas_current_time(unit, ¤t_time); 2897 } 2898 2899 return BCM_E_NONE; 2900 } 2901 #endif /* BCM_WARM_BOOT_SUPPORT */ 2902 2903 /* 2904 * Function: 2905 * bcmi_esw_tas_init 2906 * Purpose: 2907 * Internal function to initialize the software database of the tas module. 2908 * Device specific functions should also be registered in this function. 2909 * Parameters: 2910 * unit - (IN) unit number 2911 * Returns: 2912 * BCM_E_XXX 2913 */ 2914 int 2915 bcmi_esw_tas_init(int unit) 2916 { 2917 bcmi_esw_tas_control_t *tc = NULL; 2918 int rv = BCM_E_NONE; 2919 bcm_pbmp_t all_pbmp; 2920 int count, port; 2921 const tas_drv_t *td; 2922 2923 /* clean up the resource */ 2924 if (tas_control[unit] != NULL) { 2925 rv = bcmi_esw_tas_cleanup(unit); 2926 if (BCM_FAILURE(rv)) { 2927 return rv; 2928 } 2929 } 2930 2931 /* Allocate TAS control memeory for this unit. */ 2932 TAS_ALLOC(unit, tc, bcmi_esw_tas_control_t, 2933 sizeof(bcmi_esw_tas_control_t), 2934 "TAS control", 0, rv); 2935 if (BCM_FAILURE(rv)) { 2936 return rv; 2937 } 2938 2939 /* Set up the unit TAS control structure. */ 2940 tas_control[unit] = tc; 2941 2942 /* Create protection mutex. */ 2943 tc->tas_mutex = sal_mutex_create("tas_control.lock"); 2944 if (NULL == tc->tas_mutex) { 2945 bcmi_esw_tas_cleanup(unit); 2946 return (BCM_E_INTERNAL); 2947 } 2948 2949 /* Device specific information is required */ 2950 #ifdef BCM_GREYHOUND2_SUPPORT 2951 if (SOC_IS_GREYHOUND2(unit)) { 2952 rv = bcmi_gh2_tas_drv_init(unit, &tc->tas_drvs); 2953 } else 2954 #endif 2955 { 2956 rv = BCM_E_UNAVAIL; 2957 } 2958 if (BCM_FAILURE(rv)) { 2959 bcmi_esw_tas_cleanup(unit); 2960 return (rv); 2961 } 2962 2963 count = 0; 2964 BCM_PBMP_CLEAR(all_pbmp); 2965 /* Get the all valid port map */ 2966 BCM_PBMP_ASSIGN(all_pbmp, PBMP_ALL(unit)); 2967 /* Iterate the bitmap to get the maximum port number */ 2968 BCM_PBMP_ITER(all_pbmp, port) { 2969 count = port; 2970 } 2971 /* Total port counts should be (maximum port number + 1) */ 2972 count++; 2973 /* port basis profile list */ 2974 tc->profile_list_count = count; 2975 /* Allocate tc->profile_list */ 2976 TAS_ALLOC(unit, tc->profile_list, tas_profile_ctrl_t *, 2977 count * sizeof(tas_profile_ctrl_t *), 2978 "tas profiles set", 0, rv); 2979 if (BCM_FAILURE(rv)) { 2980 bcmi_esw_tas_cleanup(unit); 2981 return (BCM_E_MEMORY); 2982 } 2983 /* Allocate tc->active_pid */ 2984 TAS_ALLOC(unit, tc->active_pid, bcm_cosq_tas_profile_id_t, 2985 count * sizeof(bcm_cosq_tas_profile_id_t), 2986 "tas current pid set", 0, rv); 2987 if (BCM_FAILURE(rv)) { 2988 bcmi_esw_tas_cleanup(unit); 2989 return (BCM_E_MEMORY); 2990 } 2991 /* Allocate tc->process_pid */ 2992 TAS_ALLOC(unit, tc->process_pid, bcm_cosq_tas_profile_id_t, 2993 count * sizeof(bcm_cosq_tas_profile_id_t), 2994 "tas current pid set", 0, rv); 2995 if (BCM_FAILURE(rv)) { 2996 bcmi_esw_tas_cleanup(unit); 2997 return (BCM_E_MEMORY); 2998 } 2999 /* Allocate property software cache */ 3000 TAS_ALLOC(unit, tc->tas_properties, 3001 tas_prop_info_t, 3002 sizeof(tas_prop_info_t) * (tc->profile_list_count + 1), 3003 "TAS properties cache ", 0, rv); 3004 if (BCM_FAILURE(rv)) { 3005 bcmi_esw_tas_cleanup(unit); 3006 return (BCM_E_MEMORY); 3007 } 3008 /* Fill up the cache */ 3009 rv = bcmi_esw_tas_property_cache_init(unit); 3010 if (BCM_FAILURE(rv)) { 3011 bcmi_esw_tas_cleanup(unit); 3012 return rv; 3013 } 3014 #ifdef BCM_WARM_BOOT_SUPPORT 3015 if (!SOC_WARM_BOOT(unit)) { 3016 bcmi_esw_tas_scache_alloc(unit); 3017 } 3018 if (SOC_WARM_BOOT(unit)) { 3019 rv = bcmi_esw_tas_reinit(unit); 3020 if (BCM_FAILURE(rv)) { 3021 bcmi_esw_tas_cleanup(unit); 3022 return rv; 3023 } 3024 } 3025 #endif /* BCM_WARM_BOOT_SUPPORT */ 3026 3027 td = tc->tas_drvs; 3028 /* Allocate/init profile resource and register the profile event callback */ 3029 if (td->tas_profile_init != NULL) { 3030 rv = td->tas_profile_init(unit, bcmi_tas_profile_event_notify); 3031 } 3032 return rv; 3033 } 3034 #endif /* BCM_TAS_SUPPORT */