tas.c (66124B)
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: Greyhound2 specific TAS driver 9 */ 10 11 #include <shared/bsl.h> 12 #include <soc/drv.h> 13 #include <soc/greyhound2.h> 14 #include <bcm/cosq.h> 15 #include <bcm_int/esw_dispatch.h> 16 #include <bcm_int/esw/tas.h> 17 #include <bcm_int/esw/cosq.h> 18 #include <bcm_int/esw/greyhound2.h> 19 20 #if defined(BCM_GREYHOUND2_SUPPORT) && defined(BCM_TAS_SUPPORT) 21 /* GCLT time interval resolution : 8 ns */ 22 #define GH2_TAS_GCLT_TICKS (8) 23 /* GCLT table size */ 24 #define GH2_TAS_GCLT_ENTRIES (128) 25 /* Maximum logical port */ 26 #define GH2_TAS_MAX_PORTCNT (66) 27 /* Maximum physical port */ 28 #define GH2_MAX_PHY_PORTS (90) 29 30 /* Delay parameters for Hold Advance */ 31 /* Fixed tha overhead in bytes : SMD 8B, IPG 12B, Hold recognition time 12B */ 32 #define FIXED_THA_OVERHEAD (8 + 12 + 12) 33 34 /* Delay parameter for Gate Close Response time */ 35 /* Delay of CLMAC TXFIFO in Bytes : 4 x 48B = 192B */ 36 #define TGCR_CLMAC_TXFIFO (192) 37 /* Delay of XLMAC TXFIFO in Bytes : 4 x 32B = 128B */ 38 #define TGCR_XLMAC_TXFIFO (128) 39 /* Delay of UNIMAC TXFIFO in Bytes : 4 x 32Bytes + 16 x 128bits = 384B */ 40 #define TGCR_UNIMAC_TXFIFO (384) 41 42 /* software static data structure initialize indicator */ 43 static uint8 gh2_profile_initialized = 0; 44 45 /* GH2 TAS related interrupt/event information */ 46 typedef struct gh2_tas_event_info_s { 47 bcmi_tas_profile_event_type_t p_event; /* tas internal profile event */ 48 bcm_cosq_event_type_t event; /* bcm layer cosq event */ 49 soc_field_t mask_field; /* mask field of MEMFAILINTMASKr */ 50 soc_field_t status_field; /* status field of MEMFAILINTSTATUSr */ 51 soc_field_t clear_field; /* clear field of MEMFAILINT_CLRr */ 52 soc_reg_t sts_regs[3]; /* sub status registers to 53 indicate individual status */ 54 soc_reg_t clr_regs[3]; /* sub clear registers to 55 clear individual status */ 56 } gh2_tas_event_info_t; 57 58 /* The table lists GH2 support TAS interrupts and events */ 59 STATIC gh2_tas_event_info_t gh2_tas_event_info[] = 60 { 61 /* ToD Window event is internally used for PTP mode time caculation to fit 62 * the device HW program constrain. 63 */ 64 {bcmiTASProfileEventTODWindow , -1, 65 TOD_WINDOW_INTERRUPT_INTMASKf, 66 TOD_WINDOW_INTERRUPTf, 67 TOD_WINDOW_INTERRUPT_CLRf, 68 {-1}, 69 {-1}, 70 }, 71 {bcmiTASProfileEventProfileChange, bcmCosqEventTASProfileChange, 72 TAS_TBL_SWITCH_DONE_INTMASKf, 73 TAS_TBL_SWITCH_DONEf, 74 TAS_TBL_SWITCH_DONE_CLRf, 75 {TAS_TBL_SWITCH_DONE_0r, TAS_TBL_SWITCH_DONE_1r, TAS_TBL_SWITCH_DONE_2r}, 76 {TAS_TBL_SWITCH_DONE_CLR_0r, TAS_TBL_SWITCH_DONE_CLR_1r, 77 TAS_TBL_SWITCH_DONE_CLR_2r}, 78 }, 79 {bcmiTASProfileEventECCErr, bcmCosqEventTASECCErr, 80 TAS_PARITY_ERR_INTMASKf, 81 TAS_PARITY_ERRf, 82 TAS_PARITY_ERR_CLRf, 83 {TAS_PARITY_ERR_VLD_0r, TAS_PARITY_ERR_VLD_1r, TAS_PARITY_ERR_VLD_2r}, 84 {TAS_PARITY_ERR_CLR_0r, TAS_PARITY_ERR_CLR_1r, TAS_PARITY_ERR_CLR_2r} 85 }, 86 {bcmiTASProfileEventNextCycleTimeErr, bcmCosqEventTASNextCycleTimeErr, 87 SET_NEXT_CYCLE_TIME_ERROR_INTMASKf, 88 SET_NEXT_CYCLE_TIME_ERRORf, 89 SET_NEXT_CYCLE_TIME_ERROR_CLRf, 90 {SET_NEXT_CYCLE_TIME_ERROR_0r, SET_NEXT_CYCLE_TIME_ERROR_1r, 91 SET_NEXT_CYCLE_TIME_ERROR_2r}, 92 {SET_NEXT_CYCLE_TIME_ERROR_CLR_0r, SET_NEXT_CYCLE_TIME_ERROR_CLR_1r, 93 SET_NEXT_CYCLE_TIME_ERROR_CLR_2r}, 94 }, 95 {bcmiTASProfileEventBaseTimeErr, bcmCosqEventTASBaseTimeErr, 96 SET_BASE_TIME_ERROR_INTMASKf, 97 SET_BASE_TIME_ERRORf, 98 SET_BASE_TIME_ERROR_CLRf, 99 {SET_BASE_TIME_ERROR_0r, SET_BASE_TIME_ERROR_1r, SET_BASE_TIME_ERROR_2r}, 100 {SET_BASE_TIME_ERROR_CLR_0r, SET_BASE_TIME_ERROR_CLR_1r, 101 SET_BASE_TIME_ERROR_CLR_2r} 102 }, 103 {bcmiTASProfileEventPtrErr, bcmCosqEventTASProfilePtrErr, 104 TAS_CTL_TBL_PTR_ERR_INTMASKf, 105 TAS_CTL_TBL_PTR_ERRf, 106 TAS_CTL_TBL_PTR_ERR_CLRf, 107 {TAS_CTL_TBL_PTR_ERR_0r, TAS_CTL_TBL_PTR_ERR_1r, TAS_CTL_TBL_PTR_ERR_2r}, 108 {TAS_CTL_TBL_PTR_ERR_CLR_0r, TAS_CTL_TBL_PTR_ERR_CLR_1r, 109 TAS_CTL_TBL_PTR_ERR_CLR_2r} 110 }, 111 /* bcm layer cosq event, no corresponding HW settings. 112 * Notified by software when 'PTP out of sync' is configured.*/ 113 {-1, bcmCosqEventTASPTPOutOfSyncErr, 114 -1 115 }, 116 /* End of table, both intr_type == -1 && event == -1*/ 117 {-1, -1} 118 }; 119 120 /* Track the configured bcm cosq event and internal profile event since both 121 * events access the same interrupt resources. */ 122 typedef struct gh2_tas_event_ctrl_s { 123 sal_mutex_t event_lock; 124 SHR_BITDCL cosq_event_pbmp[_SHR_BITDCLSIZE(bcmCosqEventCount)]; 125 SHR_BITDCL tas_event_pbmp[_SHR_BITDCLSIZE(bcmiTASProfileEventCount)]; 126 } gh2_tas_event_ctrl_t; 127 128 STATIC gh2_tas_event_ctrl_t *gh2_tas_event_ctrl[BCM_MAX_NUM_UNITS]; 129 130 STATIC profile_event_cb_fn gh2_profile_event_notify[BCM_MAX_NUM_UNITS] = {NULL}; 131 132 #define GH2_TAS_EVENT_LOCK(tec) \ 133 sal_mutex_take((tec)->event_lock, sal_mutex_FOREVER); 134 #define GH2_TAS_EVENT_UNLOCK(tec) \ 135 sal_mutex_give((tec)->event_lock); 136 137 /* Essential profile information to identify the valid process interval (tod_id) 138 * and parameters used to program to HW. 139 */ 140 typedef struct gh2_tod_event_info_s { 141 uint64 tod_id; /* ptp sec time divid 64 (2^6) */ 142 bcm_ptp_timestamp_t base_time; 143 uint32 old_cycle_time; 144 uint32 new_cycle_time; 145 uint32 new_cycle_extension; 146 int config_idx; 147 profile_commit_cb_fn cb; 148 void *fn_data; 149 } gh2_tod_event_info_t; 150 151 /* Port based ToD event tracking to keep the profile information which is 152 * committed but not program to HW yet. 153 */ 154 typedef struct gh2_tod_event_control_s { 155 sal_mutex_t tod_lock; 156 gh2_tod_event_info_t *gh2_tod_event[GH2_TAS_MAX_PORTCNT]; 157 SHR_BITDCL tod_event_pbmp[_SHR_BITDCLSIZE(GH2_TAS_MAX_PORTCNT)]; 158 } gh2_tod_event_control_t; 159 160 STATIC gh2_tod_event_control_t *gh2_tod_event_control[BCM_MAX_NUM_UNITS]; 161 162 #define GH2_TOD_EVENT_LOCK(tec) \ 163 sal_mutex_take((tec)->tod_lock, sal_mutex_FOREVER); 164 #define GH2_TOD_EVENT_UNLOCK(tec) \ 165 sal_mutex_give((tec)->tod_lock); 166 167 STATIC int 168 bcmi_gh2_tas_profile_change(int unit, bcm_port_t lport); 169 STATIC int 170 bcmi_gh2_tas_profile_idx_get(int unit, bcm_port_t lport, int *config_idx); 171 STATIC int 172 bcmi_gh2_tas_control_get(int unit, bcm_port_t port, bcm_cosq_tas_control_t type, 173 int *arg); 174 175 /* HW need 500 us / 500000 ns to reflect the register settings */ 176 #define GH2_TAS_HW_REG_RESPONSE_TIME 500000 /* 500000 ns */ 177 178 /* GH2 only support 6 bit second value */ 179 #define GH2_TAS_BASETIME_SEC_MASK (0x3F) 180 181 /* Assuem GH2 need take 1 sec software process to calculate and program the 182 * required time information. 183 */ 184 #define GH2_TAS_SW_PROCESS_TIME 1 /* 1 sec */ 185 186 STATIC int 187 bcmi_gh2_tas_tod_handler(int unit); 188 /* 189 * Function: 190 * bcmi_gh2_tas_profile_event_mask_set 191 * Purpose: 192 * Configue the TAS related interrupt mask by specifying the internal 193 * profile event. 194 * For value=0 case, will be programmed when no bcm cos event reference it. 195 * Parameters: 196 * unit - (IN) unit number 197 * p_event - (IN) internal profile event 198 * val - (IN) mask value 199 * Returns: 200 * BCM_E_XXX 201 */ 202 STATIC int 203 bcmi_gh2_tas_profile_event_mask_set( 204 int unit, 205 bcmi_tas_profile_event_type_t p_event, 206 int val) 207 { 208 gh2_tas_event_info_t *e_info; 209 int i, rv = BCM_E_NONE; 210 uint32 rval; 211 gh2_tas_event_ctrl_t *tec = NULL; 212 213 if ((tec = gh2_tas_event_ctrl[unit]) == NULL) { 214 return BCM_E_INTERNAL; 215 } 216 217 if ((p_event < bcmiTASProfileEventTODWindow) || 218 (p_event >= bcmiTASProfileEventCount)) { 219 return BCM_E_PARAM; 220 } 221 GH2_TAS_EVENT_LOCK(tec); 222 if (val) { 223 SHR_BITSET(tec->tas_event_pbmp, p_event); 224 } else { 225 SHR_BITCLR(tec->tas_event_pbmp, p_event); 226 } 227 for (i = 0; ; i++) { 228 e_info = &gh2_tas_event_info[i]; 229 if ((e_info->p_event == -1) && (e_info->event == -1)) { 230 /* End of table */ 231 break; 232 } 233 234 if (e_info->p_event == p_event) { 235 if (e_info->event != -1) { 236 if (SHR_BITGET(tec->cosq_event_pbmp, e_info->event) && 237 (val == 0)) { 238 /* Do not set 0 if other event referece it */ 239 break; 240 } 241 } 242 rv = READ_MEMFAILINTMASKr(unit, &rval); 243 if (BCM_FAILURE(rv)) { 244 break; 245 } 246 soc_reg_field_set(unit, MEMFAILINTMASKr, &rval, 247 e_info->mask_field, val); 248 rv = WRITE_MEMFAILINTMASKr(unit, rval); 249 break; 250 } 251 } 252 GH2_TAS_EVENT_UNLOCK(gh2_tas_event_ctrl[unit]); 253 254 return BCM_E_NONE; 255 } 256 257 /* 258 * Function: 259 * bcmi_gh2_tas_tod_attach 260 * Purpose: 261 * Attach the profile to tod event list. 262 * Parameters: 263 * unit - (IN) unit number 264 * lport - (IN) logical port 265 * base_time - (IN) new base time 266 * old_cycle_time - (IN) old cycle time 267 * new_cycle_time - (IN) new cycle time 268 * new_cycle_extension - (IN) new cycle extension time 269 * config_idx - (IN) inactive hw index 270 * cb - (IN) cb function to call when the time information 271 * programmed to HW and kick-off the 272 * config change. 273 * fn_data - (IN) fn_data to supply in the callback 274 * Returns: 275 * BCM_E_XXX 276 */ 277 STATIC int 278 bcmi_gh2_tas_tod_attach( 279 int unit, 280 bcm_port_t lport, 281 bcm_ptp_timestamp_t base_time, 282 uint32 old_cycle_time, 283 uint32 new_cycle_time, 284 uint32 new_cycle_extension, 285 int config_idx, 286 profile_commit_cb_fn cb, 287 void *fn_data) 288 { 289 gh2_tod_event_control_t *tec = gh2_tod_event_control[unit]; 290 int rv = BCM_E_NONE; 291 gh2_tod_event_info_t *tod_event = NULL; 292 uint64 sec_hi; 293 uint32 sec_lo; 294 uint32 ns; 295 296 if (tec == NULL) { 297 return BCM_E_INTERNAL; 298 } 299 300 if (tec->gh2_tod_event[lport]) { 301 LOG_ERROR(BSL_LS_BCM_TAS, 302 (BSL_META_U(unit, 303 "gh2 tod event has been attached !\n"))); 304 return BCM_E_BUSY; 305 } 306 TAS_ALLOC(unit, tod_event, gh2_tod_event_info_t , 307 sizeof(gh2_tod_event_info_t), 308 "gh2 tod event", 0, rv); 309 310 COMPILER_64_COPY(sec_hi, base_time.seconds); 311 sec_lo = COMPILER_64_LO(base_time.seconds); 312 /* GH2 TOD window 6-bit seconds */ 313 sec_lo &= GH2_TAS_BASETIME_SEC_MASK; /* take the lowest 6 bit */ 314 /* Right shift 6 bit as the tod_id (ToD Window id) */ 315 COMPILER_64_SHR(sec_hi, 6); /* >> 6 */ 316 317 /* 318 * Caculate the target valid tod_id : 319 * At least 2 x old_cycle_time ahead new base_time to switch to new cycle 320 */ 321 ns = base_time.nanoseconds + 2 * old_cycle_time; 322 if (ns >= TAS_PTP_TIME_NANOSEC_MAX) { 323 /* wrap to 1 second */ 324 sec_lo += 1; 325 if (sec_lo > GH2_TAS_BASETIME_SEC_MASK) { 326 /* wrap to next TOD window */ 327 COMPILER_64_ADD_32(sec_hi, 1); 328 } 329 } 330 /* Prepare the related parameters */ 331 tod_event->tod_id = sec_hi; 332 memcpy(&tod_event->base_time, &base_time, sizeof(bcm_ptp_timestamp_t)); 333 tod_event->old_cycle_time = old_cycle_time; 334 tod_event->new_cycle_time = new_cycle_time; 335 tod_event->new_cycle_extension = new_cycle_extension; 336 tod_event->config_idx = config_idx; 337 tod_event->cb = cb; 338 tod_event->fn_data = fn_data; 339 340 GH2_TOD_EVENT_LOCK(tec); 341 /* Enable TOD interrupt when tod_event_pbmp is empty */ 342 if (SHR_BITNULL_RANGE(tec->tod_event_pbmp, 0, GH2_TAS_MAX_PORTCNT)) { 343 rv = bcmi_gh2_tas_profile_event_mask_set( 344 unit, bcmiTASProfileEventTODWindow, 1); 345 if (BCM_FAILURE(rv)) { 346 TAS_FREE(unit, tod_event, 0); 347 GH2_TOD_EVENT_UNLOCK(tec); 348 return rv; 349 } 350 } 351 /* Attach to the tod event list */ 352 tec->gh2_tod_event[lport] = tod_event; 353 SHR_BITSET(tec->tod_event_pbmp, lport); 354 GH2_TOD_EVENT_UNLOCK(tec); 355 356 (void)bcmi_gh2_tas_tod_handler(unit); 357 return rv; 358 } 359 360 /* 361 * Function: 362 * bcmi_gh2_tas_tod_detach 363 * Purpose: 364 * Detach the profile from tod event list. 365 * Parameters: 366 * unit - (IN) unit number 367 * lport - (IN) logical port 368 * 369 * Returns: 370 * BCM_E_XXX 371 */ 372 STATIC int 373 bcmi_gh2_tas_tod_detach(int unit, bcm_port_t lport) 374 { 375 gh2_tod_event_info_t *tod_event; 376 gh2_tod_event_control_t *tec = gh2_tod_event_control[unit]; 377 int rv = BCM_E_NONE; 378 379 if (tec == NULL) { 380 return BCM_E_INTERNAL; 381 } 382 GH2_TOD_EVENT_LOCK(tec); 383 tod_event = tec->gh2_tod_event[lport]; 384 if (tod_event) { 385 TAS_FREE(unit, tod_event, 0); 386 tec->gh2_tod_event[lport] = NULL; 387 } 388 SHR_BITCLR(tec->tod_event_pbmp, lport); 389 /* Disable TOD interrupt when tod_event_pbmp is empty */ 390 if (SHR_BITNULL_RANGE(tec->tod_event_pbmp, 0, GH2_TAS_MAX_PORTCNT)) { 391 rv = bcmi_gh2_tas_profile_event_mask_set( 392 unit, bcmiTASProfileEventTODWindow, 0); 393 } 394 GH2_TOD_EVENT_UNLOCK(tec); 395 return rv; 396 } 397 398 /* 399 * Function: 400 * bcmi_gh2_tas_tod_handler 401 * Purpose: 402 * Invoked from ToDWindow interrupt. 403 * Caculate the proper config_change_time according to current time, 404 * base_time and device limitation. 405 * The config_change_time would be (base_time + n * cycle_time) 406 * And program the time information to HW. 407 * Parameters: 408 * unit - (IN) unit number 409 * lport - (IN) logical port 410 * 411 * Returns: 412 * BCM_E_XXX 413 */ 414 STATIC int 415 bcmi_gh2_tas_tod_handler(int unit) 416 { 417 gh2_tod_event_control_t *tec = gh2_tod_event_control[unit]; 418 int i, rv, tas_enable; 419 gh2_tod_event_info_t tod; 420 bcm_ptp_timestamp_t cur_time, config_change_time; 421 uint64 cur_sec_hi, cur_sec_lo; 422 uint32 cur_ns, tmp32; 423 uint64 bt_in_ns, ct_in_ns, sec_mask; 424 SHR_BITDCL tod_event_pbmp[_SHR_BITDCLSIZE(GH2_TAS_MAX_PORTCNT)]; 425 426 if (tec == NULL) { 427 return BCM_E_INTERNAL; 428 } 429 430 GH2_TOD_EVENT_LOCK(tec); 431 SHR_BITCOPY_RANGE(tod_event_pbmp, 0, 432 tec->tod_event_pbmp, 0, 433 GH2_TAS_MAX_PORTCNT); 434 GH2_TOD_EVENT_UNLOCK(tec); 435 436 /* Iter the valid entry form tod event list */ 437 SHR_BIT_ITER(tod_event_pbmp, GH2_TAS_MAX_PORTCNT, i) { 438 BCM_IF_ERROR_RETURN( 439 bcmi_gh2_tas_control_get(unit, i, bcmCosqTASControlTASEnable, 440 &tas_enable)); 441 if (!tas_enable) { 442 continue; 443 } 444 GH2_TOD_EVENT_LOCK(tec); 445 if (tec->gh2_tod_event[i]) { 446 sal_memcpy(&tod, tec->gh2_tod_event[i], 447 sizeof(gh2_tod_event_info_t)); 448 } else { 449 GH2_TOD_EVENT_UNLOCK(tec); 450 continue; 451 } 452 GH2_TOD_EVENT_UNLOCK(tec); 453 /* Get the current time */ 454 rv = bcmi_tas_current_time(unit, &cur_time); 455 if (BCM_FAILURE(rv)) { 456 LOG_ERROR(BSL_LS_BCM_TAS, 457 (BSL_META_U(unit, 458 "Fatal error: " 459 "Fail to get current time !\n"))); 460 break; 461 } 462 COMPILER_64_COPY(cur_sec_hi, cur_time.seconds); 463 /* Right shift 6 bit as the current tod_id */ 464 COMPILER_64_SHR(cur_sec_hi, 6); 465 466 /* Check if the event need to process in this Tod Window */ 467 /* current tod_id >= target todid : process the event */ 468 if (COMPILER_64_GE(cur_sec_hi, tod.tod_id)) { 469 COMPILER_64_COPY(cur_sec_lo, cur_time.seconds); 470 COMPILER_64_SET(sec_mask, 0, GH2_TAS_BASETIME_SEC_MASK); 471 COMPILER_64_AND(cur_sec_lo, sec_mask); /* take the lowest 6 bit */ 472 ct_in_ns = bcmi_tas_ptp_to_ns(cur_time); 473 /* Need 2 x old cycle time to do the config change */ 474 cur_ns = cur_time.nanoseconds + 2 * tod.old_cycle_time; 475 if (cur_ns >= TAS_PTP_TIME_NANOSEC_MAX) { 476 COMPILER_64_ADD_32(cur_sec_lo, 1); 477 if (COMPILER_64_GT(cur_sec_lo, sec_mask)) { 478 LOG_DEBUG(BSL_LS_BCM_TAS, 479 (BSL_META_U(unit, 480 "Skip this time(tod: %d lport:%d)\n"), 481 u64_L(tod.tod_id), i)); 482 continue; 483 } 484 cur_ns -= TAS_PTP_TIME_NANOSEC_MAX; 485 } 486 COMPILER_64_ADD_32(ct_in_ns, 2 * tod.old_cycle_time); 487 /* consider HW response time */ 488 cur_ns += GH2_TAS_HW_REG_RESPONSE_TIME; 489 if (cur_ns >= TAS_PTP_TIME_NANOSEC_MAX) { 490 COMPILER_64_ADD_32(cur_sec_lo, 1); 491 if (COMPILER_64_GT(cur_sec_lo, sec_mask)) { 492 LOG_DEBUG(BSL_LS_BCM_TAS, 493 (BSL_META_U(unit, 494 "Skip this time(tod: %d lport:%d)\n"), 495 u64_L(tod.tod_id), i)); 496 continue; 497 } 498 } 499 COMPILER_64_ADD_32(ct_in_ns, GH2_TAS_HW_REG_RESPONSE_TIME); 500 501 /* consider software process time */ 502 COMPILER_64_ADD_32(cur_sec_lo, GH2_TAS_SW_PROCESS_TIME); 503 if (COMPILER_64_GT(cur_sec_lo, sec_mask)) { 504 LOG_DEBUG(BSL_LS_BCM_TAS, 505 (BSL_META_U(unit, 506 "Skip this time(tod: %d lport:%d)\n"), 507 u64_L(tod.tod_id), i)); 508 continue; 509 } 510 COMPILER_64_ADD_32(ct_in_ns, 511 GH2_TAS_SW_PROCESS_TIME * 512 TAS_PTP_TIME_NANOSEC_MAX); 513 bt_in_ns = bcmi_tas_ptp_to_ns(tod.base_time); 514 515 /* Add N x new_cycle_time until > current time */ 516 while (COMPILER_64_LT(bt_in_ns, ct_in_ns)) { 517 COMPILER_64_ADD_32(bt_in_ns, tod.new_cycle_time); 518 } 519 bcmi_tas_ns_to_ptp(bt_in_ns, &config_change_time); 520 521 /* Program to HW */ 522 tmp32 = COMPILER_64_LO(config_change_time.seconds); 523 tmp32 &= GH2_TAS_BASETIME_SEC_MASK; 524 BCM_IF_ERROR_RETURN( 525 WRITE_BASE_TIME_SECr(unit, i, tod.config_idx, 526 tmp32)); 527 BCM_IF_ERROR_RETURN( 528 WRITE_BASE_TIME_FRACr(unit, i, tod.config_idx, 529 config_change_time.nanoseconds)); 530 BCM_IF_ERROR_RETURN( 531 WRITE_CYCLE_TIMEr(unit, i, tod.config_idx, 532 tod.new_cycle_time)); 533 BCM_IF_ERROR_RETURN( 534 WRITE_CYCLE_TIME_EXTENSIONr(unit, i, tod.config_idx, 535 tod.new_cycle_extension)); 536 /* Issue config change */ 537 BCM_IF_ERROR_RETURN(bcmi_gh2_tas_profile_change(unit, i)); 538 539 /* 540 * Notify the actual config change time to common profile 541 * management layer. 542 */ 543 if (tod.cb) { 544 BCM_IF_ERROR_RETURN( 545 tod.cb(unit, i, config_change_time, tod.fn_data)); 546 } 547 /* Detach from TOD event list */ 548 BCM_IF_ERROR_RETURN(bcmi_gh2_tas_tod_detach(unit, i)); 549 } 550 } 551 return BCM_E_NONE; 552 } 553 554 /* 555 * Function: 556 * bcmi_gh2_tas_profile_schedule_config 557 * Purpose: 558 * Device specific function to schedule the proper time to program the 559 * time information to HW. Also provide the callback function to call when 560 * the time information programmed to HW and kick-off the config change. 561 * 562 * Parameters: 563 * unit - (IN) unit number 564 * lport - (IN) logical port 565 * base_time - (IN) new base time 566 * cycle_time - (IN) new cycle time 567 * cycle_extension - (IN) new cycle extension 568 * cb - (IN) cb function to call when the time information 569 * programmed to HW and kick-off the 570 * config change. 571 * fn_data - (IN) fn_data to supply in the callback 572 * 573 * Returns: 574 * BCM_E_XXX 575 */ 576 STATIC int 577 bcmi_gh2_tas_profile_schedule_config( 578 int unit, bcm_port_t lport, 579 bcm_ptp_timestamp_t base_time, 580 uint32 cycle_time, 581 uint32 cycle_extension, 582 profile_commit_cb_fn cb, 583 void *fn_data) 584 { 585 int config_idx; 586 uint32 old_cycle_time; 587 588 BCM_IF_ERROR_RETURN( 589 bcmi_gh2_tas_profile_idx_get(unit, lport, &config_idx)); 590 591 /* Need the old cycle time to calculate the config change time */ 592 BCM_IF_ERROR_RETURN( 593 READ_CYCLE_TIMEr(unit, lport, config_idx, &old_cycle_time)); 594 595 /* Attach the profile to ToD event list */ 596 return bcmi_gh2_tas_tod_attach(unit, lport, base_time, old_cycle_time, 597 cycle_time, cycle_extension, config_idx, 598 cb, fn_data); 599 } 600 601 /* 602 * Check if the port is enabled 2-level scheduling 603 * Disable it since checking mechanism is not settled yet. 604 */ 605 #define CHECK_64Q (0) 606 /* 607 * Function: 608 * bcmi_gh2_tas_port_validate 609 * Purpose: 610 * Helper function to check if the port has TAS capability. 611 * Parameters: 612 * unit - (IN) unit number 613 * Returns: 614 * BCM_E_XXX 615 */ 616 int 617 bcmi_gh2_tas_port_validate(int unit, bcm_port_t port) 618 { 619 #if CHECK_64Q 620 int is_64q_port = 0; 621 622 /* check 2-level scheduling property */ 623 if (true) { 624 soc_gh2_64q_port_check(int unit, port, *is_64q_port); 625 if (is_64q_port) { 626 /* unable to support TAS on 64Q port */ 627 return BCM_E_PARAM; 628 } 629 } 630 #endif 631 632 return BCM_E_NONE; 633 } 634 635 /* 636 * Function: 637 * bcmi_gh2_tas_disable_notify 638 * Purpose: 639 * Helper function to process what should be done when TAS is disabled. 640 * Parameters: 641 * unit - (IN) unit number 642 * port - (IN) logical port 643 * Returns: 644 * BCM_E_XXX 645 */ 646 STATIC int 647 bcmi_gh2_tas_disable_notify(int unit, bcm_port_t port) 648 { 649 /* Notify that active profile should be expired and 650 * dismiss the process profile. 651 */ 652 if (gh2_profile_event_notify[unit]) { 653 BCM_IF_ERROR_RETURN( 654 gh2_profile_event_notify[unit](unit, port, 655 bcmiTASProfileEventTASDisable)); 656 } 657 BCM_IF_ERROR_RETURN(bcmi_gh2_tas_tod_detach(unit, port)); 658 return BCM_E_NONE; 659 } 660 661 /* 662 * Function: 663 * bcmi_gh2_tas_control_set 664 * Purpose: 665 * Set various configurations for TAS. 666 * Parameters: 667 * unit - (IN) unit number 668 * port - (IN) logical port 669 * type - (IN) tas control type defined in bcm_cos_tas_control_t 670 * arg - (IN) tas control value 671 * Returns: 672 * BCM_E_XXX 673 */ 674 STATIC int 675 bcmi_gh2_tas_control_set( 676 int unit, 677 bcm_port_t port, 678 bcm_cosq_tas_control_t type, 679 int arg) 680 { 681 uint32 rval, period, ptp_mode; 682 683 BCM_IF_ERROR_RETURN(bcmi_gh2_tas_port_validate(unit, port)); 684 685 switch (type) { 686 case bcmCosqTASControlTASEnable: 687 /* GH2 valid value 0 or 1 */ 688 if ((arg < 0) || (arg > 1)) { 689 return BCM_E_PARAM; 690 } 691 BCM_IF_ERROR_RETURN(READ_TAS_CONFIG_0r(unit, port, &rval)); 692 soc_reg_field_set(unit, TAS_CONFIG_0r, &rval, 693 GATE_ENABLEDf, arg); 694 BCM_IF_ERROR_RETURN(WRITE_TAS_CONFIG_0r(unit, port, rval)); 695 if (arg == 0) { 696 BCM_IF_ERROR_RETURN(bcmi_gh2_tas_disable_notify(unit, port)); 697 } else { 698 (void)bcmi_gh2_tas_tod_handler(unit); 699 } 700 break; 701 case bcmCosqTASControlUsePTPTime: 702 /* GH2 valid value 0 or 1 */ 703 if ((arg < 0) || (arg > 1)) { 704 return BCM_E_PARAM; 705 } 706 BCM_IF_ERROR_RETURN(READ_TAS_CONFIG_0r(unit, port, &rval)); 707 soc_reg_field_set(unit, TAS_CONFIG_0r, &rval, 708 PTP_ACTIVEf, arg); 709 BCM_IF_ERROR_RETURN(WRITE_TAS_CONFIG_0r(unit, port, rval)); 710 break; 711 case bcmCosqTASControlInitGateState: 712 /* GH2 valid value to specify 8 queue in bitmap */ 713 if ((arg > 0xFF) || (arg < 0)) { 714 return BCM_E_PARAM; 715 } 716 BCM_IF_ERROR_RETURN(READ_TAS_CONFIG_2r(unit, port, &rval)); 717 soc_reg_field_set(unit, TAS_CONFIG_2r, &rval, 718 INIT_GATE_STATEf, arg); 719 BCM_IF_ERROR_RETURN(WRITE_TAS_CONFIG_2r(unit, port, rval)); 720 break; 721 case bcmCosqTASControlErrGateState: 722 /* GH2 valid value to specify 8 queue in bitmap */ 723 if (arg > 0xFF) { 724 return BCM_E_PARAM; 725 } 726 BCM_IF_ERROR_RETURN(READ_TAS_CONFIG_2r(unit, port, &rval)); 727 soc_reg_field_set(unit, TAS_CONFIG_2r, &rval, 728 ERR_GATE_STATEf, arg); 729 BCM_IF_ERROR_RETURN(WRITE_TAS_CONFIG_2r(unit, port, rval)); 730 break; 731 case bcmCosqTASControlGatePurgeEnable: 732 /* GH2 valid value 0 or 1 */ 733 if ((arg < 0) || (arg > 1)) { 734 return BCM_E_PARAM; 735 } 736 BCM_IF_ERROR_RETURN(READ_TAS_GATE_PURGE_ENABLEr(unit, port, &rval)); 737 soc_reg_field_set(unit, TAS_GATE_PURGE_ENABLEr, &rval, 738 TAS_GATE_PURGE_ENABLEf, arg); 739 BCM_IF_ERROR_RETURN(WRITE_TAS_GATE_PURGE_ENABLEr(unit, port, rval)); 740 break; 741 case bcmCosqTASControlGateControlTickInterval: 742 /* GH2 valid ragne 8ns ~ 8192 ns */ 743 if ((arg < 8) || (arg > 8192)) { 744 return BCM_E_PARAM; 745 } 746 /* From Arch document, period should be STATIC config and not allowed 747 to be changed when TAS is enabled. */ 748 BCM_IF_ERROR_RETURN(READ_TAS_CONFIG_0r(unit, port, &rval)); 749 if (soc_reg_field_get(unit, TAS_CONFIG_0r, rval, GATE_ENABLEDf)) { 750 LOG_ERROR(BSL_LS_BCM_TAS, 751 (BSL_META_UP(unit, port, "Tick Interval is not allowed " 752 "to be changed when TAS is enabled.\n"))); 753 return BCM_E_BUSY; 754 } 755 period = (arg / GH2_TAS_GCLT_TICKS) - 1; 756 BCM_IF_ERROR_RETURN(READ_GATE_CTRL_PERIODr(unit, port, &rval)); 757 soc_reg_field_set(unit, GATE_CTRL_PERIODr, &rval, 758 PERIODf, period); 759 BCM_IF_ERROR_RETURN(WRITE_GATE_CTRL_PERIODr(unit, port, rval)); 760 break; 761 case bcmCosqTASControlTASPTPLock: 762 ptp_mode = 0; 763 /* check if any tas enabled port is using ptp time */ 764 PBMP_PORT_ITER(unit, port) { 765 BCM_IF_ERROR_RETURN(READ_TAS_CONFIG_0r(unit, port, &rval)); 766 if (soc_reg_field_get(unit, TAS_CONFIG_0r, rval, GATE_ENABLEDf)) { 767 ptp_mode = soc_reg_field_get(unit, TAS_CONFIG_0r, 768 rval, PTP_ACTIVEf); 769 if (ptp_mode) { 770 break; 771 } 772 } 773 } 774 BCM_IF_ERROR_RETURN(READ_PTP_LOCKr(unit, &rval)); 775 soc_reg_field_set(unit, PTP_LOCKr, &rval, 776 PTP_LOCKf, arg); 777 BCM_IF_ERROR_RETURN(WRITE_PTP_LOCKr(unit, rval)); 778 if ((arg == 0) && (ptp_mode == 1)) { 779 /* Notify PTP out of sync */ 780 (void)bcmi_esw_cosq_handle_interrupt( 781 unit, bcmCosqEventTASPTPOutOfSyncErr, -1, -1); 782 } 783 break; 784 default: 785 return BCM_E_PARAM; 786 } 787 788 return BCM_E_NONE; 789 } 790 791 /* 792 * Function: 793 * bcmi_gh2_tas_control_get 794 * Purpose: 795 * Get various configurations for TAS 796 * Parameters: 797 * unit - (IN) unit number 798 * port - (IN) gport id 799 * type - (IN) tas control type defined in bcm_cos_tas_control_t 800 * arg - (OUT) tas control value 801 * Returns: 802 * BCM_E_XXX 803 */ 804 STATIC int 805 bcmi_gh2_tas_control_get( 806 int unit, 807 bcm_port_t port, 808 bcm_cosq_tas_control_t type, 809 int *arg) 810 { 811 uint32 rval, period; 812 813 BCM_IF_ERROR_RETURN(bcmi_gh2_tas_port_validate(unit, port)); 814 815 switch (type) { 816 case bcmCosqTASControlTASEnable: 817 BCM_IF_ERROR_RETURN(READ_TAS_CONFIG_0r(unit, port, &rval)); 818 *arg = soc_reg_field_get(unit, TAS_CONFIG_0r, rval, GATE_ENABLEDf); 819 break; 820 case bcmCosqTASControlUsePTPTime: 821 BCM_IF_ERROR_RETURN(READ_TAS_CONFIG_0r(unit, port, &rval)); 822 *arg = soc_reg_field_get(unit, TAS_CONFIG_0r, rval, PTP_ACTIVEf); 823 break; 824 case bcmCosqTASControlInitGateState: 825 BCM_IF_ERROR_RETURN(READ_TAS_CONFIG_2r(unit, port, &rval)); 826 *arg = soc_reg_field_get(unit, TAS_CONFIG_2r, rval, INIT_GATE_STATEf); 827 break; 828 case bcmCosqTASControlErrGateState: 829 BCM_IF_ERROR_RETURN(READ_TAS_CONFIG_2r(unit, port, &rval)); 830 *arg = soc_reg_field_get(unit, TAS_CONFIG_2r, rval, ERR_GATE_STATEf); 831 break; 832 case bcmCosqTASControlGatePurgeEnable: 833 BCM_IF_ERROR_RETURN(READ_TAS_GATE_PURGE_ENABLEr(unit, port, &rval)); 834 *arg = soc_reg_field_get(unit, TAS_GATE_PURGE_ENABLEr, rval, 835 TAS_GATE_PURGE_ENABLEf); 836 break; 837 case bcmCosqTASControlGateControlTickInterval: 838 BCM_IF_ERROR_RETURN(READ_GATE_CTRL_PERIODr(unit, port, &rval)); 839 period = soc_reg_field_get(unit, GATE_CTRL_PERIODr, rval, PERIODf); 840 *arg = (period + 1) * GH2_TAS_GCLT_TICKS; 841 break; 842 case bcmCosqTASControlTASPTPLock: 843 BCM_IF_ERROR_RETURN(READ_PTP_LOCKr(unit, &rval)); 844 *arg = soc_reg_field_get(unit, PTP_LOCKr, rval, PTP_LOCKf); 845 break; 846 default: 847 return BCM_E_PARAM; 848 } 849 return BCM_E_NONE; 850 } 851 852 /* 853 * Function: 854 * bcmi_gh2_tas_status_get 855 * Purpose: 856 * Get TAS status by specifying the type. 857 * Parameters: 858 * unit - (IN) unit number 859 * port - (IN) gport id 860 * type - (IN) tas status type defined in bcm_cos_tas_status_t 861 * arg - (OUT) tas status value 862 * Returns: 863 * BCM_E_XXX 864 */ 865 STATIC int 866 bcmi_gh2_tas_status_get( 867 int unit, 868 bcm_port_t port, 869 bcm_cosq_tas_status_t type, 870 int *arg) 871 { 872 uint32 rval; 873 int auto_adjust_txoverrun = 0, auto_adjust_phold = 0; 874 875 BCM_IF_ERROR_RETURN(bcmi_gh2_tas_port_validate(unit, port)); 876 877 switch (type) { 878 case bcmCosqTASStatusGateQueueState: 879 BCM_IF_ERROR_RETURN(READ_COS_QUEUEr(unit, port, &rval)); 880 *arg = soc_reg_field_get(unit, COS_QUEUEr, rval, GATE_STATEf); 881 break; 882 case bcmCosqTASStatusGateStateSet: 883 BCM_IF_ERROR_RETURN(READ_COS_QUEUEr(unit, port, &rval)); 884 *arg = soc_reg_field_get(unit, COS_QUEUEr, rval, GATE_STATE_SELECTf); 885 break; 886 case bcmCosqTASStatusTickGranularity: 887 *arg = GH2_TAS_GCLT_TICKS; 888 break; 889 case bcmCosqTASStatusMaxCalendarEntries: 890 bcmi_esw_tas_property_get(unit, TAS_PROP_TXOVERRUN, 891 port, -1, &auto_adjust_txoverrun); 892 bcmi_esw_tas_property_get(unit, TAS_PROP_HOLDADVANCE, 893 port, -1, &auto_adjust_phold); 894 if (auto_adjust_txoverrun || auto_adjust_phold) { 895 *arg = GH2_TAS_GCLT_ENTRIES / 2; 896 } else { 897 *arg = GH2_TAS_GCLT_ENTRIES; 898 } 899 break; 900 default: 901 return BCM_E_PARAM; 902 } 903 return BCM_E_NONE; 904 } 905 906 /* 907 * Purpose: 908 * Get the hold advance time in ns 909 * Description: 910 * Tha = (Thrt - Tgor) where Thrt is the hold response time which depends on 911 * Min_final_fragment_size and Min_non_final_fragment_size. 912 * The minimum of Tgor(gate open response time) has to be considered in order to 913 * make sure a preemptable frame never delays an express frame 914 */ 915 STATIC int 916 bcmi_gh2_tas_tha_get( 917 int unit, 918 bcm_port_t lport, 919 int *tha) 920 { 921 bcm_gport_t gport; 922 int speed, bit_tick_ps; 923 uint32 non_final_frag_size, final_frag_size; 924 925 if (tha == NULL) { 926 return BCM_E_PARAM; 927 } 928 /* Get port speed -> caculate bit time in picosecond */ 929 BCM_IF_ERROR_RETURN(bcm_esw_port_speed_get(unit, lport, &speed)); 930 if (!speed) { 931 BCM_IF_ERROR_RETURN(bcm_esw_port_speed_max(unit, lport, &speed)); 932 } 933 if (!speed) { 934 speed = SOC_CONTROL(unit)->info.port_speed_max[lport]; 935 } 936 /* speed in Mbps, bit time in ps: 10^6/speed */ 937 bit_tick_ps = 1000000 / speed; 938 939 BCM_IF_ERROR_RETURN(bcm_esw_port_gport_get(unit, lport, &gport)); 940 BCM_IF_ERROR_RETURN( 941 bcm_esw_port_preemption_control_get( 942 unit, gport, bcmPortPreemptControlNonFinalFragSizeTx, 943 &non_final_frag_size)); 944 BCM_IF_ERROR_RETURN( 945 bcm_esw_port_preemption_control_get( 946 unit, gport, bcmPortPreemptControlFinalFragSizeTx, 947 &final_frag_size)); 948 /* Fixed time : SMD 8B, IPG 12B, Hold recognition time 12B */ 949 *tha = FIXED_THA_OVERHEAD * 8 * bit_tick_ps / 1000; 950 /* Variable time : according to frag size */ 951 *tha += (non_final_frag_size + final_frag_size) * 8 * bit_tick_ps / 1000; 952 953 LOG_DEBUG(BSL_LS_BCM_TAS, 954 (BSL_META_U(unit, "Tha (speed %d, non-frag %d frag %d ) %d ns\n"), 955 speed, non_final_frag_size, final_frag_size, *tha)); 956 return BCM_E_NONE; 957 } 958 959 /* 960 * Get the bytes in the edatabuf to compute worst case value of 961 * T-edatabuf (flush time to cleanup the fifo) 962 */ 963 STATIC int 964 bcmi_gh2_tas_tgcr_edatabuf_fifo_get( 965 int unit, 966 bcm_port_t port, 967 int *pkt_bytes) 968 { 969 soc_info_t *si; 970 int phy_port, sub_ports, pkt_cnt, shift, group, start, pkt_size; 971 SHR_BITDCL pbmp[_SHR_BITDCLSIZE(GH2_MAX_PHY_PORTS)]; 972 973 if (pkt_bytes == NULL) { 974 return BCM_E_PARAM; 975 } 976 BCM_IF_ERROR_RETURN( 977 READ_EGR_TDM_PORT_MAPm(unit, MEM_BLOCK_ALL, 0, (void *)&pbmp)); 978 979 si = &SOC_INFO(unit); 980 phy_port = si->port_l2p_mapping[port]; 981 982 /* 983 * phy port group in EGR_TDM_PORT_MAPm bitmap 984 * GE0:2-9, GE1:10-17, GE2:18-25, GE3:26-33, ... GE6: 50-57 985 * XL0:58-59, XL1:60-61 ......XL13:84-85 986 * CL0: 86-89 987 */ 988 if (phy_port < 58) { 989 /* < 58 : GE port, start from 2, 8 ports as a group.*/ 990 shift = 2; 991 group = 8; 992 } else if (phy_port < 86) { 993 /* >=58, < 86: XL port, start from 58, 2 ports as a group */ 994 shift = 58; 995 group = 2; 996 } else if (phy_port < 90) { 997 /* >= 86, < 90: CL port, start from 86, 4 ports as a group */ 998 shift = 86; 999 group = 4; 1000 } else { 1001 return BCM_E_PARAM; 1002 } 1003 /* Find port belongs to which group and find the start of it */ 1004 start = (((phy_port - shift) / group) * group) + shift; 1005 /* Caculate how many ports are valid in this group */ 1006 SHR_BITCOUNT_RANGE(pbmp, sub_ports, start, group); 1007 1008 /* 1009 * For Edatabuf FIFO flush time, under different configurations 1010 * (sub-port count), the total packets be sent (pkt.cnt * pkt.size) are 1011 * listed below. 1012 * The data is for express packets only. If preempt packets are considered, 1013 * the time should be doubled. For time caculation, we assume the case of 1014 * express packet. 1015 * 1016 * port-group sub-port pkt.cnt pkt.size 1017 * GE 8 5 224 1018 * GE 4 10 224 1019 * GE 2 20 224 1020 * GE 1 24 224 1021 * XL 2 14 224 1022 * XL 1 24 224 1023 * CL 4 20 288 1024 * CL 2 24 288 1025 * CL 1 24 288 1026 */ 1027 if (phy_port < 58) { 1028 /* GE port case */ 1029 if (sub_ports == 8) { 1030 pkt_cnt = 5; 1031 } else if (sub_ports == 4) { 1032 pkt_cnt = 10; 1033 } else if (sub_ports == 2) { 1034 pkt_cnt = 20; 1035 } else { 1036 pkt_cnt = 24; 1037 } 1038 pkt_size = 224; 1039 } else if (phy_port < 86) { 1040 /* XL port case phy_port < 86 */ 1041 if (sub_ports == 2) { 1042 pkt_cnt = 14; 1043 } else { 1044 pkt_cnt = 24; 1045 } 1046 pkt_size = 224; 1047 } else { 1048 /* The invalid phy_port check has been done.*/ 1049 if (sub_ports == 4) { 1050 pkt_cnt = 20; 1051 } else if (sub_ports == 2) { 1052 pkt_cnt = 24; 1053 } else { 1054 pkt_cnt = 24; 1055 } 1056 pkt_size = 288; 1057 } 1058 *pkt_bytes = pkt_cnt * pkt_size; 1059 1060 LOG_DEBUG(BSL_LS_BCM_TAS, 1061 (BSL_META_U(unit, 1062 "tgcr_edatabuf_fifo phy_port %d subport %d " 1063 "pkt_bytes %d \n"), 1064 phy_port, sub_ports, *pkt_bytes)); 1065 return BCM_E_NONE; 1066 } 1067 1068 /* T-txpkt (depends on queueMaxSDU) */ 1069 /* 1070 * Get the bit time(in ns) of the maximum value of MaxSDU(maximum service data 1071 * unit) among the specified queue map. 1072 */ 1073 STATIC int 1074 bcmi_gh2_tas_tgcr_txpkt_get( 1075 int unit, 1076 bcm_port_t port, 1077 uint32 qmap, 1078 int *tgcr_txpkt) 1079 { 1080 int c; 1081 int prop; 1082 int maxsdu = 0; 1083 int speed, bit_tick_ps; 1084 1085 if (tgcr_txpkt == NULL) { 1086 return BCM_E_PARAM; 1087 } 1088 for (c = 0; c < BCM_COS_COUNT; c++) { 1089 if (qmap & (1 << c)) { 1090 BCM_IF_ERROR_RETURN( 1091 bcmi_esw_tas_property_get(unit, TAS_PROP_MAXSDU, port, 1092 c, &prop)); 1093 /* keep the largest one */ 1094 if (prop > maxsdu) { 1095 maxsdu = prop; 1096 } 1097 } 1098 } 1099 /* Get port speed -> caculate bit time in picosecond */ 1100 BCM_IF_ERROR_RETURN(bcm_esw_port_speed_get(unit, port, &speed)); 1101 if (!speed) { 1102 BCM_IF_ERROR_RETURN(bcm_esw_port_speed_max(unit, port, &speed)); 1103 } 1104 if (!speed) { 1105 speed = SOC_CONTROL(unit)->info.port_speed_max[port]; 1106 } 1107 1108 /* speed in Mbps, bit time in ps: 10^6/speed */ 1109 bit_tick_ps = 1000000 / speed; 1110 1111 *tgcr_txpkt = maxsdu * 8 * bit_tick_ps / 1000; 1112 1113 LOG_DEBUG(BSL_LS_BCM_TAS, 1114 (BSL_META_U(unit, 1115 "Dynamic tgcr (speed %d, Qmap %08x, max_sdu %d) " 1116 "%d ns \n"), 1117 speed, qmap, maxsdu, *tgcr_txpkt)); 1118 return BCM_E_NONE; 1119 } 1120 1121 /* 1122 * Get the Tgcr exclude the T-txpkt which could be queue-dependent. 1123 * The 'fixed' means its queue-independent, the port speed and attribute 1124 * decide the tgcr_fixed. This value is fixed across entries in calendar table. 1125 */ 1126 STATIC int 1127 bcmi_gh2_tas_tgcr_fixed_get(int unit, bcm_port_t port, int *tgcr_fixed) 1128 { 1129 soc_info_t *si; 1130 int delay_param; 1131 int freq, core_tick_ns; 1132 int speed, bit_tick_ps; 1133 int tdm_size, txpfc_enable, edatabuf_bytes, pkt_bytes, top_fifo_delay; 1134 1135 if (tgcr_fixed == NULL) { 1136 return BCM_E_PARAM; 1137 } 1138 si = &SOC_INFO(unit); 1139 /* Get core clock freq in MHz */ 1140 freq = si->frequency; 1141 /* core tick in ns : 10^3/freq */ 1142 core_tick_ns = 1000 / freq; 1143 1144 /* Get port speed -> caculate bit time in picosecond */ 1145 BCM_IF_ERROR_RETURN(bcm_esw_port_speed_get(unit, port, &speed)); 1146 if (!speed) { 1147 BCM_IF_ERROR_RETURN(bcm_esw_port_speed_max(unit, port, &speed)); 1148 } 1149 if (!speed) { 1150 speed = SOC_CONTROL(unit)->info.port_speed_max[port]; 1151 } 1152 1153 /* speed in Mbps, bit time in ps: 10^6/speed */ 1154 bit_tick_ps = 1000000 / speed; 1155 1156 /* T-gs-async-fifo = 3 core clk */ 1157 delay_param = 3 * core_tick_ns; 1158 1159 /* T-egr-tdm : Worst TDM miss penalty for MMU dequeue = 1160 * (Max TDM interval - 1) x Cycle Time(ns) */ 1161 BCM_IF_ERROR_RETURN(soc_gh2_tdm_size_get(unit, &tdm_size)); 1162 delay_param += (tdm_size - 1) * core_tick_ns; 1163 1164 /* T-edatabuf */ 1165 BCM_IF_ERROR_RETURN( 1166 bcmi_gh2_tas_tgcr_edatabuf_fifo_get(unit, port, &edatabuf_bytes)); 1167 delay_param += edatabuf_bytes * 8 * bit_tick_ps / 1000; 1168 1169 /* T-mactxfifo */ 1170 if (IS_CL_PORT(unit, port)) { 1171 /* 4 x 48B = 192B */ 1172 pkt_bytes = TGCR_CLMAC_TXFIFO; 1173 /* PM 4x25_top fifo delay = 15.51 ns */ 1174 top_fifo_delay = 16; 1175 } else if (IS_XL_PORT(unit, port)) { 1176 /* 4 x 32B = 128B */ 1177 pkt_bytes = TGCR_XLMAC_TXFIFO; 1178 /* PM 4x10_top fifo delay = 15.51 ns */ 1179 top_fifo_delay = 16; 1180 } else if (IS_GE_PORT(unit, port)) { 1181 /* 4 x 32B + 16 x 128b = 384B */ 1182 pkt_bytes = TGCR_UNIMAC_TXFIFO; 1183 top_fifo_delay = 0; 1184 } else { 1185 return BCM_E_PARAM; 1186 } 1187 /* also consider the 80/64 encoding */ 1188 delay_param += pkt_bytes * 8 * 80 / 64 * bit_tick_ps / 1000; 1189 delay_param += top_fifo_delay; 1190 1191 /* T-pfc */ 1192 BCM_IF_ERROR_RETURN( 1193 bcm_esw_port_control_get(unit, port, bcmPortControlPFCTransmit, 1194 &txpfc_enable)); 1195 if (txpfc_enable) { 1196 /* pfc frame size = 64B */ 1197 delay_param += 64 * 8 * bit_tick_ps / 1000; 1198 } 1199 *tgcr_fixed = delay_param; 1200 1201 LOG_DEBUG(BSL_LS_BCM_TAS, 1202 (BSL_META_U(unit, "Fixed tgcr (core clk %d, tdm size %d, " 1203 "speed %d, pfc enable %d, " 1204 "edatabuf fifo %d, port fifo %d, " 1205 "port top fifo %d) %d ns \n"), 1206 freq, tdm_size, speed, txpfc_enable, edatabuf_bytes, 1207 pkt_bytes, top_fifo_delay, *tgcr_fixed)); 1208 return BCM_E_NONE; 1209 } 1210 1211 /* 1212 * Function: 1213 * bcmi_gh2_tas_profile_delay_param_get 1214 * Purpose: 1215 * Helper function to get the device-specific delay parameters which are 1216 * used to do the profile entry remap. 1217 * 1218 * Parameters: 1219 * unit - (IN) unit number 1220 * tas_delay_param - (IN) TAS_DPARAM_xxx to specify which delay param 1221 * port - (IN) logical port 1222 * qmap - (IN) queue bitmap, optional and valid for type 1223 * TAS_DPARAM_TGCR_DYNAMIC. 1224 * value - (OUT) value in ns 1225 * Returns: 1226 * BCM_E_XXX 1227 */ 1228 STATIC int 1229 bcmi_gh2_tas_profile_delay_param_get( 1230 int unit, 1231 int tas_delay_param, 1232 bcm_port_t port, 1233 uint32 qmap, 1234 int *value) 1235 { 1236 int rv = BCM_E_NONE; 1237 1238 if (value == NULL) { 1239 return BCM_E_PARAM; 1240 } 1241 BCM_IF_ERROR_RETURN(bcmi_gh2_tas_port_validate(unit, port)); 1242 1243 switch (tas_delay_param) { 1244 case (TAS_DPARAM_TGCR_FIXED): 1245 rv = bcmi_gh2_tas_tgcr_fixed_get(unit, port, value); 1246 break; 1247 case (TAS_DPARAM_TGCR_DYNAMIC): 1248 rv = bcmi_gh2_tas_tgcr_txpkt_get(unit, port, qmap, value); 1249 break; 1250 case (TAS_DPARAM_THA): 1251 rv = bcmi_gh2_tas_tha_get(unit, port, value); 1252 break; 1253 default: 1254 return BCM_E_UNAVAIL; 1255 } 1256 return rv; 1257 } 1258 1259 /* 1260 * Basetime compare against CurrentTime + Tmargin 1261 * if Basetime < CurrentTime + Tmargin return BCM_E_NONE 1262 * otherwise return BCM_E_TIMEOUT which is for user application to increase 1263 * the config change error) 1264 */ 1265 STATIC int 1266 bcmi_gh2_tas_profile_basetime_check(int unit, bcm_ptp_timestamp_t basetime) 1267 { 1268 bcm_ptp_timestamp_t cur_time; 1269 uint64 bt_in_ns, ct_in_ns, tmargin; 1270 int len; 1271 uint32 max_cycle_time; 1272 1273 if (BCM_FAILURE(bcmi_tas_current_time(unit, &cur_time))) { 1274 LOG_ERROR(BSL_LS_BCM_TAS, 1275 (BSL_META_U(unit, 1276 "Fatal error: " 1277 "Fail to get current time !\n"))); 1278 return BCM_E_INTERNAL; 1279 } 1280 ct_in_ns = bcmi_tas_ptp_to_ns(cur_time); 1281 bt_in_ns = bcmi_tas_ptp_to_ns(basetime); 1282 1283 COMPILER_64_ZERO(tmargin); 1284 /* worse case of the 2 times of cycle time */ 1285 len = soc_reg_field_length(unit, CYCLE_TIMEr, CYCLE_TIMEf); 1286 max_cycle_time = (1 << len) - 1; 1287 COMPILER_64_ADD_32(tmargin, 2 * max_cycle_time); 1288 COMPILER_64_ADD_32(tmargin, GH2_TAS_HW_REG_RESPONSE_TIME); 1289 COMPILER_64_ADD_32(tmargin, 1290 GH2_TAS_SW_PROCESS_TIME * TAS_PTP_TIME_NANOSEC_MAX); 1291 1292 LOG_DEBUG(BSL_LS_BCM_TAS, 1293 (BSL_META_U(unit, "Tmargin in GH2 {0x%x 0x%x} \n"), 1294 COMPILER_64_HI(tmargin), COMPILER_64_LO(tmargin))); 1295 1296 COMPILER_64_ADD_64(ct_in_ns, tmargin); 1297 if (COMPILER_64_GT(ct_in_ns, bt_in_ns)) { 1298 return BCM_E_TIMEOUT; 1299 } 1300 return BCM_E_NONE; 1301 } 1302 1303 /* 1304 * Function: 1305 * bcmi_gh2_tas_profile_idx_get 1306 * Purpose: 1307 * Get the inactive hw index. We need to program to the inactive sets 1308 * Parameters: 1309 * unit - (IN) unit number 1310 * lport - (IN) logical port 1311 * config_idx - (OUT) inactive hw index 1312 * Returns: 1313 * BCM_E_XXX 1314 */ 1315 STATIC int 1316 bcmi_gh2_tas_profile_idx_get(int unit, bcm_port_t lport, int *config_idx) 1317 { 1318 uint32 rval; 1319 int active_idx; 1320 1321 BCM_IF_ERROR_RETURN(READ_TAS_CONFIG_1r(unit, lport, &rval)); 1322 active_idx = soc_reg_field_get(unit, TAS_CONFIG_1r, rval, ACTIVE_SETf); 1323 *config_idx = 1 - active_idx; 1324 return BCM_E_NONE; 1325 } 1326 1327 /* 1328 * gh2_mmu_gate_ctl_tbl : 1329 * valid port 2-65, valid idx 0-1 1330 */ 1331 static const soc_mem_t gh2_mmu_gate_ctl_tbl[66][2] = 1332 { 1333 {INVALIDm, INVALIDm}, 1334 {INVALIDm, INVALIDm}, 1335 {MMU_GATE_CTL_TBL0_P2m, MMU_GATE_CTL_TBL1_P2m}, 1336 {MMU_GATE_CTL_TBL0_P3m, MMU_GATE_CTL_TBL1_P3m}, 1337 {MMU_GATE_CTL_TBL0_P4m, MMU_GATE_CTL_TBL1_P4m}, 1338 {MMU_GATE_CTL_TBL0_P5m, MMU_GATE_CTL_TBL1_P5m}, 1339 {MMU_GATE_CTL_TBL0_P6m, MMU_GATE_CTL_TBL1_P6m}, 1340 {MMU_GATE_CTL_TBL0_P7m, MMU_GATE_CTL_TBL1_P7m}, 1341 {MMU_GATE_CTL_TBL0_P8m, MMU_GATE_CTL_TBL1_P8m}, 1342 {MMU_GATE_CTL_TBL0_P9m, MMU_GATE_CTL_TBL1_P9m}, 1343 {MMU_GATE_CTL_TBL0_P10m, MMU_GATE_CTL_TBL1_P10m}, 1344 {MMU_GATE_CTL_TBL0_P11m, MMU_GATE_CTL_TBL1_P11m}, 1345 {MMU_GATE_CTL_TBL0_P12m, MMU_GATE_CTL_TBL1_P12m}, 1346 {MMU_GATE_CTL_TBL0_P13m, MMU_GATE_CTL_TBL1_P13m}, 1347 {MMU_GATE_CTL_TBL0_P14m, MMU_GATE_CTL_TBL1_P14m}, 1348 {MMU_GATE_CTL_TBL0_P15m, MMU_GATE_CTL_TBL1_P15m}, 1349 {MMU_GATE_CTL_TBL0_P16m, MMU_GATE_CTL_TBL1_P16m}, 1350 {MMU_GATE_CTL_TBL0_P17m, MMU_GATE_CTL_TBL1_P17m}, 1351 {MMU_GATE_CTL_TBL0_P18m, MMU_GATE_CTL_TBL1_P18m}, 1352 {MMU_GATE_CTL_TBL0_P19m, MMU_GATE_CTL_TBL1_P19m}, 1353 {MMU_GATE_CTL_TBL0_P20m, MMU_GATE_CTL_TBL1_P20m}, 1354 {MMU_GATE_CTL_TBL0_P21m, MMU_GATE_CTL_TBL1_P21m}, 1355 {MMU_GATE_CTL_TBL0_P22m, MMU_GATE_CTL_TBL1_P22m}, 1356 {MMU_GATE_CTL_TBL0_P23m, MMU_GATE_CTL_TBL1_P23m}, 1357 {MMU_GATE_CTL_TBL0_P24m, MMU_GATE_CTL_TBL1_P24m}, 1358 {MMU_GATE_CTL_TBL0_P25m, MMU_GATE_CTL_TBL1_P25m}, 1359 {MMU_GATE_CTL_TBL0_P26m, MMU_GATE_CTL_TBL1_P26m}, 1360 {MMU_GATE_CTL_TBL0_P27m, MMU_GATE_CTL_TBL1_P27m}, 1361 {MMU_GATE_CTL_TBL0_P28m, MMU_GATE_CTL_TBL1_P28m}, 1362 {MMU_GATE_CTL_TBL0_P29m, MMU_GATE_CTL_TBL1_P29m}, 1363 {MMU_GATE_CTL_TBL0_P30m, MMU_GATE_CTL_TBL1_P30m}, 1364 {MMU_GATE_CTL_TBL0_P31m, MMU_GATE_CTL_TBL1_P31m}, 1365 {MMU_GATE_CTL_TBL0_P32m, MMU_GATE_CTL_TBL1_P32m}, 1366 {MMU_GATE_CTL_TBL0_P33m, MMU_GATE_CTL_TBL1_P33m}, 1367 {MMU_GATE_CTL_TBL0_P34m, MMU_GATE_CTL_TBL1_P34m}, 1368 {MMU_GATE_CTL_TBL0_P35m, MMU_GATE_CTL_TBL1_P35m}, 1369 {MMU_GATE_CTL_TBL0_P36m, MMU_GATE_CTL_TBL1_P36m}, 1370 {MMU_GATE_CTL_TBL0_P37m, MMU_GATE_CTL_TBL1_P37m}, 1371 {MMU_GATE_CTL_TBL0_P38m, MMU_GATE_CTL_TBL1_P38m}, 1372 {MMU_GATE_CTL_TBL0_P39m, MMU_GATE_CTL_TBL1_P39m}, 1373 {MMU_GATE_CTL_TBL0_P40m, MMU_GATE_CTL_TBL1_P40m}, 1374 {MMU_GATE_CTL_TBL0_P41m, MMU_GATE_CTL_TBL1_P41m}, 1375 {MMU_GATE_CTL_TBL0_P42m, MMU_GATE_CTL_TBL1_P42m}, 1376 {MMU_GATE_CTL_TBL0_P43m, MMU_GATE_CTL_TBL1_P43m}, 1377 {MMU_GATE_CTL_TBL0_P44m, MMU_GATE_CTL_TBL1_P44m}, 1378 {MMU_GATE_CTL_TBL0_P45m, MMU_GATE_CTL_TBL1_P45m}, 1379 {MMU_GATE_CTL_TBL0_P46m, MMU_GATE_CTL_TBL1_P46m}, 1380 {MMU_GATE_CTL_TBL0_P47m, MMU_GATE_CTL_TBL1_P47m}, 1381 {MMU_GATE_CTL_TBL0_P48m, MMU_GATE_CTL_TBL1_P48m}, 1382 {MMU_GATE_CTL_TBL0_P49m, MMU_GATE_CTL_TBL1_P49m}, 1383 {MMU_GATE_CTL_TBL0_P50m, MMU_GATE_CTL_TBL1_P50m}, 1384 {MMU_GATE_CTL_TBL0_P51m, MMU_GATE_CTL_TBL1_P51m}, 1385 {MMU_GATE_CTL_TBL0_P52m, MMU_GATE_CTL_TBL1_P52m}, 1386 {MMU_GATE_CTL_TBL0_P53m, MMU_GATE_CTL_TBL1_P53m}, 1387 {MMU_GATE_CTL_TBL0_P54m, MMU_GATE_CTL_TBL1_P54m}, 1388 {MMU_GATE_CTL_TBL0_P55m, MMU_GATE_CTL_TBL1_P55m}, 1389 {MMU_GATE_CTL_TBL0_P56m, MMU_GATE_CTL_TBL1_P56m}, 1390 {MMU_GATE_CTL_TBL0_P57m, MMU_GATE_CTL_TBL1_P57m}, 1391 {MMU_GATE_CTL_TBL0_P58m, MMU_GATE_CTL_TBL1_P58m}, 1392 {MMU_GATE_CTL_TBL0_P59m, MMU_GATE_CTL_TBL1_P59m}, 1393 {MMU_GATE_CTL_TBL0_P60m, MMU_GATE_CTL_TBL1_P60m}, 1394 {MMU_GATE_CTL_TBL0_P61m, MMU_GATE_CTL_TBL1_P61m}, 1395 {MMU_GATE_CTL_TBL0_P62m, MMU_GATE_CTL_TBL1_P62m}, 1396 {MMU_GATE_CTL_TBL0_P63m, MMU_GATE_CTL_TBL1_P63m}, 1397 {MMU_GATE_CTL_TBL0_P64m, MMU_GATE_CTL_TBL1_P64m}, 1398 {MMU_GATE_CTL_TBL0_P65m, MMU_GATE_CTL_TBL1_P65m}, 1399 }; 1400 /* 1401 * Function: 1402 * bcmi_gh2_tas_profile_param_check 1403 * Purpose: 1404 * Validate the parameters in bcm profile structure 1405 * Parameters: 1406 * unit - (IN) unit number 1407 * profile - (IN) bcm tas profile structure 1408 * 1409 * Returns: 1410 * BCM_E_XXX 1411 */ 1412 STATIC int 1413 bcmi_gh2_tas_profile_param_check(int unit, bcm_cosq_tas_profile_t *profile) 1414 { 1415 soc_mem_t gclt_mem = MMU_GATE_CTL_TBL0_P2m; 1416 bcm_cosq_tas_entry_t *tas_entry; 1417 int i, field_len; 1418 1419 for (i = 0; i < profile->num_entries; i++) { 1420 tas_entry = &profile->entries[i]; 1421 if (tas_entry->ticks == BCM_COSQ_TAS_ENTRY_TICKS_STAY) { 1422 field_len = soc_mem_field_length(unit, gclt_mem, TIME_INTERVALf); 1423 /* AND the 0xFFF for ticks_stay value */ 1424 tas_entry->ticks &= (1 << field_len) - 1; 1425 } 1426 BCM_IF_ERROR_RETURN(soc_mem_field32_fit(unit, gclt_mem, TIME_INTERVALf, 1427 tas_entry->ticks)); 1428 BCM_IF_ERROR_RETURN(soc_mem_field32_fit(unit, gclt_mem, GATE_STATEf, 1429 tas_entry->state)); 1430 } 1431 1432 BCM_IF_ERROR_RETURN( 1433 soc_reg_field_validate(unit, CYCLE_TIMEr, CYCLE_TIMEf, 1434 profile->ptp_cycle_time)); 1435 BCM_IF_ERROR_RETURN( 1436 soc_reg_field_validate(unit, CYCLE_TIME_EXTENSIONr, 1437 CYCLE_TIME_EXTENSIONf, 1438 profile->ptp_max_cycle_extension)); 1439 1440 return BCM_E_NONE; 1441 } 1442 1443 /* 1444 * Function: 1445 * bcmi_gh2_tas_profile_entries_write 1446 * Purpose: 1447 * Program the profile entries to HW 1448 * Parameters: 1449 * unit - (IN) unit number 1450 * lport - (IN) logical port 1451 * config_idx - (IN) hw config idx 1452 * entries - (IN) profile entries 1453 * num_entries - (IN) number of entries 1454 * 1455 * Returns: 1456 * BCM_E_XXX 1457 */ 1458 STATIC int 1459 bcmi_gh2_tas_profile_entries_write( 1460 int unit, 1461 bcm_port_t lport, 1462 int config_idx, 1463 bcm_cosq_tas_entry_t *entries, 1464 int num_entries) 1465 { 1466 int i, idx_max; 1467 mmu_gate_ctl_tbl0_p2_entry_t *gclt_entry; 1468 uint8 *gclt_buf = NULL; 1469 uint8 phold = 0; 1470 int rv; 1471 soc_mem_t gclt_mem = MMU_GATE_CTL_TBL0_P2m; 1472 soc_memacc_t memacc_phold, memacc_interval, memacc_gstate; 1473 bcm_cosq_tas_entry_t *tas_entry; 1474 soc_info_t *si; 1475 int phy_port, mmu_port; 1476 1477 if ((soc_memacc_init(unit, gclt_mem, PHOLD_REQf, &memacc_phold)) || 1478 (soc_memacc_init(unit, gclt_mem, TIME_INTERVALf, &memacc_interval)) || 1479 (soc_memacc_init(unit, gclt_mem, GATE_STATEf, &memacc_gstate))) { 1480 return BCM_E_PARAM; 1481 } 1482 1483 TAS_ALLOC(unit, gclt_buf, uint8, 1484 num_entries * sizeof(mmu_gate_ctl_tbl0_p2_entry_t), 1485 "TAS GCLT buffer", 1, rv); 1486 if (BCM_FAILURE(rv)) { 1487 return rv; 1488 } 1489 1490 idx_max = num_entries; 1491 for (i = 0; i < idx_max; i++) { 1492 tas_entry = &entries[i]; 1493 if (tas_entry->flags & BCM_COSQ_TAS_ENTRY_F_PREEMPT) { 1494 phold = 1; 1495 } else { 1496 phold = 0; 1497 } 1498 gclt_entry = 1499 soc_mem_table_idx_to_pointer(unit, gclt_mem, 1500 mmu_gate_ctl_tbl0_p2_entry_t *, 1501 gclt_buf, 1502 i); 1503 soc_memacc_field32_set(&memacc_gstate, gclt_entry, tas_entry->state); 1504 soc_memacc_field32_set(&memacc_phold, gclt_entry, phold); 1505 soc_memacc_field32_set(&memacc_interval, gclt_entry, tas_entry->ticks); 1506 1507 } 1508 1509 si = &SOC_INFO(unit); 1510 phy_port = si->port_l2p_mapping[lport]; 1511 mmu_port = si->port_p2m_mapping[phy_port]; 1512 rv = soc_mem_write_range(unit, gh2_mmu_gate_ctl_tbl[mmu_port][config_idx], 1513 MEM_BLOCK_ALL, 0, (idx_max - 1), gclt_buf); 1514 if (BCM_FAILURE(rv)) { 1515 TAS_FREE(unit, gclt_buf, 1); 1516 return rv; 1517 } 1518 TAS_FREE(unit, gclt_buf, 1); 1519 1520 return BCM_E_NONE; 1521 } 1522 1523 /* 1524 * Function: 1525 * bcmi_gh2_tas_profile_change 1526 * Purpose: 1527 * Issue config change to start switching to new profile. 1528 * Parameters: 1529 * unit - (IN) unit number 1530 * lport - (IN) logical port 1531 * Returns: 1532 * BCM_E_XXX 1533 */ 1534 STATIC int 1535 bcmi_gh2_tas_profile_change(int unit, bcm_port_t lport) 1536 { 1537 uint32 rval; 1538 1539 /* HW detect 0 to 1 change to start switching to new cycles.*/ 1540 BCM_IF_ERROR_RETURN(READ_TAS_CONFIG_0r(unit, lport, &rval)); 1541 soc_reg_field_set(unit, TAS_CONFIG_0r, &rval, CONFIG_CHANGEf, 0); 1542 BCM_IF_ERROR_RETURN(WRITE_TAS_CONFIG_0r(unit, lport, rval)); 1543 soc_reg_field_set(unit, TAS_CONFIG_0r, &rval, CONFIG_CHANGEf, 1); 1544 BCM_IF_ERROR_RETURN(WRITE_TAS_CONFIG_0r(unit, lport, rval)); 1545 1546 return BCM_E_NONE; 1547 } 1548 1549 /* 1550 * Function: 1551 * bcmi_gh2_tas_handle_interrupt 1552 * Purpose: 1553 * Invoked when TAS related interrupts happen. 1554 * Dispatch to corresponding callback according to the interrupt. 1555 * Parameters: 1556 * unit - (IN) unit number 1557 * lport - (IN) logical port 1558 * Returns: 1559 * BCM_E_XXX 1560 */ 1561 STATIC int 1562 bcmi_gh2_tas_handle_interrupt(int unit) 1563 { 1564 int i, group, p; 1565 uint32 rval, sts; 1566 gh2_tas_event_info_t *e_info; 1567 gh2_tas_event_ctrl_t *tec = NULL; 1568 SHR_BITDCL cosq_event_pbmp[_SHR_BITDCLSIZE(bcmCosqEventCount)]; 1569 SHR_BITDCL tas_event_pbmp[_SHR_BITDCLSIZE(bcmiTASProfileEventCount)]; 1570 bcm_port_t lport, mmu_port, phy_port; 1571 soc_reg_t sts_reg, clr_reg; 1572 soc_info_t *si; 1573 uint8 event_cb = 0, intr_cb = 0; 1574 1575 si = &SOC_INFO(unit); 1576 if ((tec = gh2_tas_event_ctrl[unit]) == NULL) { 1577 return BCM_E_INTERNAL; 1578 } 1579 1580 rval = 0; 1581 BCM_IF_ERROR_RETURN(READ_MEMFAILINTSTATUSr(unit, &rval)); 1582 1583 if (bsl_check(bslLayerBcm, bslSourceTas, bslSeverityDebug, unit)) { 1584 bcm_ptp_timestamp_t cur_time; 1585 (void)bcmi_tas_current_time (unit, &cur_time); 1586 LOG_DEBUG(BSL_LS_BCM_TAS, 1587 (BSL_META_U(unit, "intr sts 0x%x \n"), rval)); 1588 } 1589 1590 GH2_TAS_EVENT_LOCK(tec); 1591 SHR_BITCOPY_RANGE(cosq_event_pbmp, 0, 1592 tec->cosq_event_pbmp, 0, 1593 bcmCosqEventCount); 1594 SHR_BITCOPY_RANGE(tas_event_pbmp, 0, 1595 tec->tas_event_pbmp, 0, 1596 bcmiTASProfileEventCount); 1597 GH2_TAS_EVENT_UNLOCK(tec); 1598 1599 for (i = 0; ; i++) { 1600 e_info = &gh2_tas_event_info[i]; 1601 if ((e_info->p_event == -1) && (e_info->event == -1)) { 1602 /* End of table */ 1603 break; 1604 } 1605 /* 1606 * PTP outofsync is not triggered by interrupt. 1607 * For this event, when user config the bcmCosqTASControlTASPTPLock = 0, 1608 * bcmi_esw_cosq_handle_interrupt will be notified from that. 1609 */ 1610 if (e_info->p_event == -1) { 1611 continue; 1612 } 1613 /* Check the status to see which event causes the interrupt. */ 1614 if (!soc_reg_field_get(unit, MEMFAILINTSTATUSr, rval, 1615 e_info->status_field)) { 1616 continue; 1617 } 1618 if (e_info->event != -1) { 1619 if (SHR_BITGET(cosq_event_pbmp, e_info->event)) { 1620 event_cb = 1; 1621 } 1622 } 1623 if (SHR_BITGET(tas_event_pbmp, e_info->p_event)) { 1624 intr_cb = 1; 1625 } 1626 1627 if ((sts_reg = e_info->sts_regs[0]) != -1) { 1628 /* Report the event by port */ 1629 for (group = 0; group < 3; group++) { 1630 sts_reg = e_info->sts_regs[group]; 1631 clr_reg = e_info->clr_regs[group]; 1632 sts = 0; 1633 /* Check the per event status register to get 1634 * which port causes the interrupt. 1635 */ 1636 soc_reg32_get(unit, sts_reg, REG_PORT_ANY, 0, &sts); 1637 if (sts == 0) { 1638 continue; 1639 } 1640 for (p = 0; p < 32; p++) { 1641 if (sts & (1 << p)) { 1642 mmu_port = group * 32 + p; 1643 phy_port = si->port_m2p_mapping[mmu_port]; 1644 lport = si->port_p2l_mapping[phy_port]; 1645 if (event_cb) { 1646 (void)bcmi_esw_cosq_handle_interrupt( 1647 unit, e_info->event, lport, 1648 BCM_COS_INVALID); 1649 } 1650 if (intr_cb) { 1651 /* profile change event */ 1652 (void)gh2_profile_event_notify[unit]( 1653 unit, lport, e_info->p_event); 1654 } 1655 } 1656 } 1657 /* Clear sub status (write 1 clear) */ 1658 soc_reg32_set(unit, clr_reg, REG_PORT_ANY, 0, sts); 1659 } 1660 } else { 1661 /* TOD Window system event */ 1662 if (intr_cb) { 1663 (void)bcmi_gh2_tas_tod_handler(unit); 1664 } 1665 } 1666 /* Clear status (write 1 clear) */ 1667 rval = 0; 1668 BCM_IF_ERROR_RETURN(READ_MEMFAILINT_CLRr(unit, &rval)); 1669 soc_reg_field_set(unit, MEMFAILINT_CLRr, &rval, 1670 e_info->clear_field, 1); 1671 BCM_IF_ERROR_RETURN(WRITE_MEMFAILINT_CLRr(unit, rval)); 1672 } 1673 return BCM_E_NONE; 1674 } 1675 1676 /* 1677 * Function: 1678 * bcmi_gh2_cosq_event_mask_set 1679 * Purpose: 1680 * Configue the TAS related interrupt mask by specifying bcm cosq event. 1681 * For value=0 case, will be programmed when no other internal profile event 1682 * reference it. 1683 * Parameters: 1684 * unit - (IN) unit number 1685 * event_type - (IN) bcm cosq event 1686 * val - (IN) mask value 1687 * Returns: 1688 * BCM_E_XXX 1689 */ 1690 int 1691 bcmi_gh2_cosq_event_mask_set( 1692 int unit, 1693 bcm_cosq_event_type_t event_type, 1694 int val) 1695 { 1696 gh2_tas_event_info_t *e_info; 1697 int i, rv = BCM_E_NONE; 1698 uint32 rval; 1699 gh2_tas_event_ctrl_t *tec = NULL; 1700 1701 if ((tec = gh2_tas_event_ctrl[unit]) == NULL) { 1702 return BCM_E_INTERNAL; 1703 } 1704 1705 GH2_TAS_EVENT_LOCK(tec); 1706 if (val) { 1707 SHR_BITSET(tec->cosq_event_pbmp, event_type); 1708 } else { 1709 SHR_BITCLR(tec->cosq_event_pbmp, event_type); 1710 } 1711 1712 for (i = 0; ; i++) { 1713 e_info = &gh2_tas_event_info[i]; 1714 if ((e_info->p_event == -1) && (e_info->event == -1)) { 1715 /* End of table */ 1716 break; 1717 } 1718 if (e_info->event == bcmCosqEventTASPTPOutOfSyncErr) { 1719 continue; 1720 } 1721 if (e_info->event == event_type) { 1722 if (e_info->p_event != -1) { 1723 if (SHR_BITGET(tec->tas_event_pbmp, e_info->p_event) && 1724 (val == 0)) { 1725 /* Donot set 0 if other event referece it */ 1726 break; 1727 } 1728 } 1729 rv = READ_MEMFAILINTMASKr(unit, &rval); 1730 if (BCM_FAILURE(rv)) { 1731 break; 1732 } 1733 soc_reg_field_set(unit, MEMFAILINTMASKr, &rval, 1734 e_info->mask_field, val); 1735 rv = WRITE_MEMFAILINTMASKr(unit, rval); 1736 break; 1737 } 1738 } 1739 1740 GH2_TAS_EVENT_UNLOCK(tec); 1741 1742 return BCM_E_NONE; 1743 } 1744 /* 1745 * Device specific function for bcmi_esw_cosq_event_validate. 1746 */ 1747 int 1748 bcmi_gh2_cosq_events_validate(int unit, bcm_cosq_event_types_t event_types) 1749 { 1750 bcm_cosq_event_type_t e_type; 1751 gh2_tas_event_info_t *e_info; 1752 int i, rv = BCM_E_NONE; 1753 1754 if (!soc_feature(unit, soc_feature_tas)) { 1755 return BCM_E_UNAVAIL; 1756 } 1757 1758 for (e_type = 0; e_type < bcmCosqEventCount; ++e_type) { 1759 if (BCM_COSQ_EVENT_TYPE_GET(event_types, e_type)) { 1760 for (i = 0; ; i++) { 1761 e_info = &gh2_tas_event_info[i]; 1762 if ((e_info->p_event == -1) && (e_info->event == -1)) { 1763 /* End of table */ 1764 break; 1765 } 1766 if (e_info->event == e_type) { 1767 break; 1768 } 1769 } 1770 } 1771 } 1772 1773 return rv; 1774 } 1775 1776 /* 1777 * Function: 1778 * bcmi_gh2_tas_profile_deinit 1779 * Purpose: 1780 * Free the resource associated with the tas internal profile 1781 * Parameters: 1782 * unit - (IN) unit number 1783 * Returns: 1784 * BCM_E_XXX 1785 */ 1786 STATIC int 1787 bcmi_gh2_tas_profile_deinit(int unit) 1788 { 1789 int i, rv; 1790 gh2_tas_event_info_t *e_info; 1791 1792 /* Disable the profile change interrupt */ 1793 gh2_profile_event_notify[unit] = NULL; 1794 1795 if (gh2_tod_event_control[unit] != NULL) { 1796 /* detach all TOD event */ 1797 for (i = 0; i < GH2_TAS_MAX_PORTCNT; i++) { 1798 (void)bcmi_gh2_tas_tod_detach(unit, i); 1799 } 1800 if (gh2_tod_event_control[unit]->tod_lock) { 1801 sal_mutex_destroy(gh2_tod_event_control[unit]->tod_lock); 1802 gh2_tod_event_control[unit]->tod_lock = NULL; 1803 } 1804 TAS_FREE(unit, gh2_tod_event_control[unit], 0); 1805 gh2_tod_event_control[unit] = NULL; 1806 } 1807 1808 if (gh2_tas_event_ctrl[unit] != NULL) { 1809 /* Disable the profile event interrupt */ 1810 for (i = 0; ; i++) { 1811 e_info = &gh2_tas_event_info[i]; 1812 if (e_info->p_event == -1) { 1813 /* End of table */ 1814 break; 1815 } 1816 rv = bcmi_gh2_tas_profile_event_mask_set( 1817 unit, e_info->p_event, 0); 1818 if (BCM_FAILURE(rv)) { 1819 return rv; 1820 } 1821 } 1822 if (gh2_tas_event_ctrl[unit]->event_lock) { 1823 sal_mutex_destroy(gh2_tas_event_ctrl[unit]->event_lock); 1824 gh2_tas_event_ctrl[unit]->event_lock = NULL; 1825 } 1826 TAS_FREE(unit, gh2_tas_event_ctrl[unit], 0); 1827 gh2_tas_event_ctrl[unit] = NULL; 1828 } 1829 return BCM_E_NONE; 1830 } 1831 /* 1832 * Function: 1833 * bcmi_gh2_tas_profile_init 1834 * Purpose: 1835 * initialize the tas internal profile 1836 * Parameters: 1837 * unit - (IN) unit number 1838 * cb - (IN) callback function for profile event notification 1839 * Returns: 1840 * BCM_E_XXX 1841 */ 1842 STATIC int 1843 bcmi_gh2_tas_profile_init(int unit, profile_event_cb_fn cb) 1844 { 1845 int i, rv; 1846 gh2_tas_event_info_t *e_info; 1847 1848 /* Initialize the structure, function ptr to NULL */ 1849 if (gh2_profile_initialized == 0) { 1850 for (i = 0; i < BCM_MAX_NUM_UNITS; i++) { 1851 gh2_profile_event_notify[i] = NULL; 1852 gh2_tod_event_control[i] = NULL; 1853 gh2_tas_event_ctrl[i] = NULL; 1854 } 1855 gh2_profile_initialized = 1; 1856 } 1857 1858 /* Allocate/initialize the GH2 tas profile event control structure */ 1859 if (gh2_tas_event_ctrl[unit] == NULL) { 1860 TAS_ALLOC(unit, gh2_tas_event_ctrl[unit], 1861 gh2_tas_event_ctrl_t, sizeof(gh2_tas_event_ctrl_t), 1862 "GH2 TAS event control ", 0, rv); 1863 if (BCM_FAILURE(rv)) { 1864 return BCM_E_INIT; 1865 } 1866 gh2_tas_event_ctrl[unit]->event_lock = 1867 sal_mutex_create("tas_event.lock"); 1868 if (gh2_tas_event_ctrl[unit]->event_lock == NULL) { 1869 bcmi_gh2_tas_profile_deinit(unit); 1870 return BCM_E_INIT; 1871 } 1872 } 1873 1874 /* Assign the profile event notify callback */ 1875 gh2_profile_event_notify[unit] = cb; 1876 1877 /* Allocate/initialize the GH2 tas TOD event control structure */ 1878 if (gh2_tod_event_control[unit] == NULL) { 1879 TAS_ALLOC(unit, gh2_tod_event_control[unit], 1880 gh2_tod_event_control_t, sizeof(gh2_tod_event_control_t), 1881 "TOD event handler ", 0, rv); 1882 if (BCM_FAILURE(rv)) { 1883 bcmi_gh2_tas_profile_deinit(unit); 1884 return BCM_E_INIT; 1885 } 1886 gh2_tod_event_control[unit]->tod_lock = 1887 sal_mutex_create("tas_tod.lock"); 1888 if (gh2_tod_event_control[unit]->tod_lock == NULL) { 1889 bcmi_gh2_tas_profile_deinit(unit); 1890 return BCM_E_INIT; 1891 } 1892 for (i = 0; i < GH2_TAS_MAX_PORTCNT; i++) { 1893 gh2_tod_event_control[unit]->gh2_tod_event[i] = NULL; 1894 } 1895 sal_memset(gh2_tod_event_control[unit]->tod_event_pbmp, 0, 1896 _SHR_BITDCLSIZE(GH2_TAS_MAX_PORTCNT) * sizeof(SHR_BITDCL)); 1897 } 1898 1899 /* Enable the profile event interrupt */ 1900 for (i = 0; ; i++) { 1901 e_info = &gh2_tas_event_info[i]; 1902 if (e_info->p_event == -1) { 1903 /* End of table */ 1904 break; 1905 } 1906 /* Skip the TOD event during init enable it when required */ 1907 if (e_info->p_event == bcmiTASProfileEventTODWindow) { 1908 continue; 1909 } 1910 rv = bcmi_gh2_tas_profile_event_mask_set( 1911 unit, e_info->p_event, 1); 1912 if (BCM_FAILURE(rv)) { 1913 bcmi_gh2_tas_profile_deinit(unit); 1914 return rv; 1915 } 1916 } 1917 1918 return BCM_E_NONE; 1919 } 1920 1921 /* Driver functions to implement device-specific operations. 1922 * dispatched from common layer functions. 1923 */ 1924 STATIC const tas_drv_t gh2_tas_drv = { 1925 bcmi_gh2_tas_control_set, 1926 bcmi_gh2_tas_control_get, 1927 bcmi_gh2_tas_status_get, 1928 bcmi_gh2_tas_profile_init, 1929 bcmi_gh2_tas_profile_deinit, 1930 bcmi_gh2_tas_profile_param_check, 1931 bcmi_gh2_tas_profile_basetime_check, 1932 bcmi_gh2_tas_profile_delay_param_get, 1933 bcmi_gh2_tas_profile_idx_get, 1934 bcmi_gh2_tas_profile_entries_write, 1935 bcmi_gh2_tas_profile_schedule_config, 1936 bcmi_gh2_tas_profile_change 1937 }; 1938 1939 /* 1940 * Function: 1941 * bcmi_gh2_tas_drv_init 1942 * Purpose: 1943 * initialize the tas device-driver 1944 * Parameters: 1945 * unit - (IN) unit number 1946 * Returns: 1947 * BCM_E_XXX 1948 */ 1949 int 1950 bcmi_gh2_tas_drv_init(int unit, const tas_drv_t **tas_drv) 1951 { 1952 1953 *tas_drv = &gh2_tas_drv; 1954 BCM_IF_ERROR_RETURN( 1955 soc_gh2_cosq_event_handler_register( 1956 unit, bcmi_gh2_tas_handle_interrupt)); 1957 1958 return BCM_E_NONE; 1959 } 1960 #endif /* BCM_GREYHOUND2_SUPPORT && BCM_TAS_SUPPORT */